C语言 将数据馈送到fwrite()缓冲区的正确方法

njthzxwz  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(89)

当输入数据保存在一个二维数组中并且每一列都必须保存到一个单独的文件中时,是否有一个最佳实践来说明如何将数据馈送到fwrite()?
下面的示例模拟从文件(“buffer”)读取的数据,该文件被处理并解析为8行x 3列数组(“processedData”)。接下来的一个循环为每一列创建一个新的文件指针,通过一次阅读一列并保存每个文件来填充该指针。这将产生3个文件,每个文件8个字节。
是否有更有效的方法将列数据提供给fwrite(),而不是一次循环遍历数组内容的一列?

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    uint8_t t, p, s;

    // Assume inputFile is a buffer with the contents of a file from disk

    uint8_t buffer[24] = {2, 1, 3, 3, 2, 4, 4, 3, 5, 5, 4, 6, 6, 5, 7, 7, 6, 8, 8, 7, 9, 9, 8, 0};

    uint8_t(*processedData)[8][3] = malloc(sizeof *processedData);
    memset(processedData, '\0', sizeof(*processedData));

    // Assume the contents of the buffer are processed in some way...

    for (s = 0; s < 24; s++)
        (*processedData)[s % 8][s % 3] = buffer[s];

    // Parse the processed content by column and save in 3 separate files

    for (t = 0; t < 3; t++)
    {
        uint8_t *hld = (uint8_t *)calloc(8, sizeof(uint8_t));

        for (p = 0; p < 8; p++)
            hld[p] = (*processedData)[p][t];

        char *fileName = (char *)malloc(sizeof(char) * 30);
        sprintf(fileName, "%s-%u", "TestFile", t);

        FILE *tmpFile = fopen(fileName, "w+");
        if (tmpFile == NULL)
        {
            fputs("File error", stderr);
            exit(1);
        }

        fwrite(hld, 1, 8, tmpFile);

        fclose(tmpFile);
        free(hld);
    }

    return 0;
}

字符串

2hh7jdfx

2hh7jdfx1#

您的方法可以工作,但有点麻烦,并有几个问题:

  • 由于内容看起来是二进制的,因此应使用"wb"以二进制模式打开文件。
  • 不需要"w+"中的+,其允许除了写入之外从文件阅读。
  • 文件名和hld数组似乎不需要内存分配。“
  • 如果您确实分配了内存,则应该检查分配失败,并确保释放了所有已分配块。
  • 使用uint8_t作为循环索引变量是容易出错。
  • 将1D数组分配到2D数组中时,行索引应使用s / 3而不是s % 8
  • sprintf没有缓冲区溢出保护:则应改用snprintf()

关于您的问题:* 是否有更有效的方法将列数据提供给fwrite(),而不是一次一列地循环数组内容?*
由于分栏式数据不是连续的字节集,因此您必须以某种方式逐一查看2D数组,才能收集要输出的数据。请注意,不需要使用fwrite,您可以直接对每个字节使用fputc,而不需要中间的hld数组。然而,如果数据元素大于一个字节,或者如果应用程序是多线程的,则在数组中收集数据并使用单个fwrite可能更容易、更高效。只要确保输出文件以二进制模式打开即可。
以下是修改后的版本:

#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROWS  8
#define COLS  3

int main(int argc, char *argv[]) {
    // Assume inputFile is a buffer with the contents of a file from disk
    uint8_t buffer[ROWS * COLS] = { 2, 1, 3, 3, 2, 4, 4, 3, 5, 5, 4, 6, 6, 5, 7, 7, 6, 8, 8, 7, 9, 9, 8, 0 };
    uint8_t (*processedData)[COLS] = calloc(ROWS, sizeof *processedData);
    if (processedData == NULL) {
        fprintf(stderr, "cannot allocate %dx%d array: %s\n", ROWS, COLS, strerror(errno));
        exit(1);
    }
    // Assume the contents of the buffer are processed in some way...
    for (int s = 0; s < ROWS * COLS; s++) {
        processedData[s / COLS][s % COLS] = buffer[s];
    }
    // Parse the processed content by column and save in 3 separate files
    for (int t = 0; t < COLS; t++) {
        char fileName[30];
        uint8_t hld[ROWS];
        for (int i = 0; i < ROWS; i++) {
            hld[i] = processedData[i][t];
        }
        snprintf(fileName, sizeof fileName, "TestFile-%u", t);
        FILE *tmpFile = fopen(fileName, "wb");
        if (tmpFile == NULL) {
            fprintf(stderr, "cannot open %s: %s\n", fileName, strerror(errno));
            exit(1);
        }
        fwrite(hld, sizeof(*hld), ROWS, tmpFile);
        fclose(tmpFile);
    }
    free(processedData);
    return 0;
}

字符串
还要注意,processedData可以直接指向buffer,从而避免了分配和初始化的需要:

// use buffer as a packed 2D array
    uint8_t (*processedData)[COLS] = (uint8_t(*)[COLS])buffer;

相关问题