fwrite()替代32位系统上的大文件

时间:2013-05-13 10:26:42

标签: c windows file-io

我正在尝试使用C代码生成大文件(4-8 GB)。 现在我使用带有fopen()参数的'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);

3 个答案:

答案 0 :(得分:2)

在Windows上创建大文件时不应该有任何问题,但我注意到如果你在文件上使用32位版本的搜索,那么它似乎决定它是一个32位文件,因此不能大于4GB。在Windows上使用&gt; 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 ++怪癖)。

<强>更新

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

#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来改善这一点。

答案 1 :(得分: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

赋值运算符(*=)将作用于l值(unsigned long long int),因此您可以信任它对64位值起作用。

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

答案 2 :(得分:1)

Yuo 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