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

我基本上是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中。

 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字节的维度。

我怎样才能有更大的二进制文件?

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

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

您可以写入超过4GB的内容,但只需调用一次fwrite 。 您需要一次拨打不超过4GB的多个电话。

无论如何,这肯定是解决问题的更好方法。 您当前的方法涉及分配一个巨大的内存块。 解决方法将允许您分配较小的内存块,从而减少对系统内存的需求。

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

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

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

  2. 你把它写到文件中。 它返回磁盘,位于不同的位置。

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

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

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

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

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

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

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