10

我正在尝试使用 C 代码生成大文件(4-8 GB)。现在我使用fopen()with'wb'参数打开文件二进制文件并循环fwrite()运行for以将字节写入文件。我在每次循环迭代中写一个字节。在文件大于或等于 4294967296 字节 (4096 MB) 之前没有问题。它看起来像 32 位操作系统中的一些内存限制,因为当它写入打开的文件时,它仍然在 RAM 中。我对吗?症状是创建的文件比我想要的要小。区别是 4096 MB,例如,当我想要 6000 MB 文件时,它会创建 6000 MB - 4096 MB = 1904 MB 文件。

你能建议其他方法来完成这项任务吗?

问候 :)

部分代码:

unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB
char x[1]={atoi(argv[2])};

fp=fopen(strcat(argv[3],".bin"),"wb");

    for(i=0;i<number_of_data;i++) {
        fwrite(x, sizeof(x[0]), sizeof(x[0]), fp);
    }

fclose(fp);
4

3 回答 3

2

fwrite不是这里的问题。问题是您正在计算的值number_of_data

在处理 64 位整数时,您需要小心任何无意的 32 位转换。当我定义它们时,我通常在许多离散的步骤中进行,每一步都要小心:

unsigned long long int number_of_data = atoi(argv[1]); // Should be good for up to 2,147,483,647 MB (2TB)
number_of_data *= 1024*1024; // Convert to MB

赋值运算符 ( *=) 将作用于左值 (the unsigned long long int),因此您可以相信它作用于 64 位值。

这可能看起来没有优化,但一个体面的编译器会删除任何不必要的步骤。

于 2013-05-13T13:45:03.580 回答
2

在 Windows 上创建大文件应该没有任何问题,但我注意到,如果您在文件上使用 32 位版本的 seek,那么它似乎会确定它是 32 位文件,因此不能大于 4GB。在 Windows 上处理 >4GB 文件时,我已经成功使用 _open、_lseeki64 和 _write。例如:

static void
create_file_simple(const TCHAR *filename, __int64 size)
{
    int omode = _O_WRONLY | _O_CREAT | _O_TRUNC;
    int fd = _topen(filename, omode, _S_IREAD | _S_IWRITE);
    _lseeki64(fd, size, SEEK_SET);
    _write(fd, "ABCD", 4);
    _close(fd);
}

以上将毫无问题地创建一个超过 4GB 的文件。但是,它可能会很慢,因为当您在那里调用 _write() 时,文件系统必须实际为您分配磁盘块。如果您必须随机填充它,您可能会发现创建稀疏文件更快。如果您从头开始按顺序填充文件,那么上面的代码就可以了。请注意,如果您真的想使用 fwrite 提供的缓冲 IO,您可以使用 fdopen() 从 C 库文件描述符中获取 FILE*。

(如果有人想知道,TCHAR、_topen 和下划线前缀都是 MSVC++ 的怪癖)。

更新

最初的问题是对值 V 的 N 个字节使用顺序输出。因此,一个实际应该生成所需文件的简单程序是:

#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <io.h>
#include <tchar.h>
int
_tmain(int argc, TCHAR *argv[])
{
    __int64 n = 0, r = 0, size = 0x100000000LL; /* 4GB */
    char v = 'A';
    int fd = _topen(argv[1], _O_WRONLY | _O_CREAT| _O_TRUNC, _S_IREAD | _S_IWRITE);
    while (r != -1 && n < count) {
        r = _write(fd, &v, sizeof(value));
        if (r >= 0) n += r;
    }
    _close(fd);
    return 0;
}

但是,这将非常慢,因为我们一次只写入一个字节。这可以通过使用更大的缓冲区或通过在描述符 (fd) 上调用 fdopen 并切换到 fwrite 来使用缓冲 I/O 来改进。

于 2013-05-13T11:03:30.473 回答
1

余没有问题fwrite()。问题似乎是你的

unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB

这确实应该是

uint16_t number_of_data = atoll(argv[1])*1024ULL*1024ULL;

unsigned long long仍然可以,但无论您的目标变量有多大,unsigned int * int * int都会给您一个。unsinged int

于 2013-05-13T12:29:38.437 回答