首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >32位系统上大文件的fwrite()替代方法

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

Stack Overflow用户
提问于 2013-05-13 18:26:42
回答 3查看 2.8K关注 0票数 10

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

你能推荐其他的方法来完成这项任务吗?

致敬:)

部分代码:

代码语言:javascript
复制
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);
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-05-13 21:45:04

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

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

代码语言:javascript
复制
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
EN

Stack Overflow用户

发布于 2013-05-13 19:03:30

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

代码语言:javascript
复制
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);
}

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

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

更新

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

代码语言:javascript
复制
#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;
}

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

票数 2
EN

Stack Overflow用户

发布于 2013-05-13 20:29:38

你对fwrite()没有问题。问题似乎出在你的

代码语言:javascript
复制
unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB

它实际上应该类似于

代码语言:javascript
复制
uint16_t number_of_data = atoll(argv[1])*1024ULL*1024ULL;

unsigned long long仍然没问题,但是不管你的目标变量有多大,unsigned int * int * int都会给你一个unsinged int

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16519834

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档