C - fwrite大于4GB的二进制文件

时间:2013-09-09 09:07:06

标签: c

我基本上是C的新手。

我有一个64位Windows7,64 GB RAM和240 GB SSD。

我使用一个采集板,将采集的数据存储在2个内部FIFO中,然后将数据传递到RAM(因此我可以获取,比方说,60 GB的数据)。

我无法做的是使用fwrite函数来编写大小超过4 GB的二进制文件。

这是我的变量:

static UINT64      *rbuffer12 = NULL;
static UINT64      *rbuffer34 = NULL;
FILE               *fd_raw, *fd_raw2;
UINT64             nacq = 2000;
ICS1555_ULONG_T    bufferLength12, bufferLength34;

因此,关注FIFO#1中发生的事情,电路板使nacq采集大小为bufferLength12,并使用rbuffer12指向的存储器将所有内容存储在RAM中。 / p>

bufferLength12 = 524288;
acq_length = 524288 / (channels_number * 2 * 4);
nBytes = bufferLength12 * 4;

rbuffer12 = (UINT64 *) malloc(nacq*nBytes);
memset(rbuffer12, 0, nacq*nBytes);

for (i = 0; i < 4*nacq; i++)
 ReadF(h, 0, (UINT64 *) (rbuffer12 + i * bufferLength12/8), nBytes/4, NULL, 0))

现在我想将数据写入File12.bin

fd_raw=fopen("File12.bin","wb")
fwrite((UINT64 *) rbuffer12,8,(nacq * 4 * channels_number * acq_length) ,fd_raw);
fclose(fd_raw);
fd_raw=NULL;

当我设置nacq=2000时,文件大小为4'096'000字节。如果我试图增加这个值,程序会挂起,如果我退出采集,我会得到一个二进制文件,例如,1'960'000字节的维度。

如何拥有更大的二进制文件?

3 个答案:

答案 0 :(得分:8)

您在评论中说明您的编译器是MSVC 2008并且您的目标是x64。

我怀疑你被运行时库错误所困扰。例如,请参阅此帖子:https://web.archive.org/web/20140316203229/connect.microsoft.com/VisualStudio/feedback/details/755018/fwrite-hangs-with-large-size-count

您可以写入超过4GB的内容,但只需拨打一次fwrite即可完成此操作。您需要一次拨打不超过4GB的多个电话。

在任何情况下,这肯定是解决问题的更好方法。您当前的方法涉及分配一个巨大的内存块。这种解决方法可以让你分配更小的内存块,从而减少对系统内存的需求。

答案 1 :(得分:2)

另一个答案涵盖了几乎所有内容。我想指出你没有做你认为自己在做的事情。具体来说,请记住,物理RAM中的每个页面都可以由页面文件(交换文件)中的页面支持。将数据写入内存数组时,您编写的每个页面在写入时仅访问一次。然后它会闲置很长一段时间,直到你完成了你的收购并想要写出来。在您不使用操作系统的同时,操作系统会将数据分页到磁盘。

当您将其“写入”文件时,您正在做的是:

  1. 您可以在缓冲区的开头访问数据。此时此数据很可能被分页到磁盘,因为它已经很老了。它可能仍然存在于RAM中,尽管它同时位于磁盘上 - 这可能出现在电池供电的系统中,现代操作系统一直在将过时的RAM溢出到磁盘以使休眠更快。如果它不在RAM中,操作系统将处理页面错误并为您读回数据。

  2. 您将其写入文件。它会返回磁盘,位于不同的位置。

  3. 因此数据会从磁盘往返磁盘。这可能不是你想要的。

    您可以通过三种方式处理它。

    1. 不要使用系统范围的页面文件,而是让操作系统将您的文件用作页面文件。你可以通过内存映射你的文件,然后简单地写入内存。关闭映射时,可以保证所有内存页最终都在文件中。没有往返。

    2. 有两个线程和一组互锁缓冲区。一个线程填充缓冲区,另一个线程将它们转储到磁盘。互锁可以防止两个线程踩到其他人的脚趾上。这使您可以使用阻止调用,如果您对winapi不太熟悉,可能更容易处理。

    3. 有一个线程但使用非阻塞I / O.这样你就可以“写”到磁盘而无需等待数据实际到达那里。有一些图书馆可以帮助您,boost可能是一个不错的选择。

答案 2 :(得分:0)

我可能会遗漏一些东西,但对我来说,在fread和fwrite耗尽气体之后的明显选择是使用(最初的Win32)函数集CreateFile,ReadFile,WriteFile和CloseHandle。他们的能力要强得多,我认为/猜测你正在使用的f函数是它们周围的包装。

由于他们更有能力,他们有点难学,但嘿,文件I / O不是火箭科学。如果您使用一组I / O函数实现了代码,那么您将不会失去使用这些函数的方法。