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中的每个页面都可以由页面文件(交换文件)中的页面支持。 将数据写入内存数组时,您编写的每个页面在写入时仅访问一次。 然后它会闲置很长一段时间,直到你完成了你的收购并想要写出来。 在您不使用操作系统的同时,操作系统会将数据分页到磁盘。
当您将其“写入”文件时,您正在做的是:
-
您可以在缓冲区的开头访问数据。 此时此数据很可能被分页到磁盘,因为它已经很老了。 它可能仍然在RAM中,尽管它同时位于磁盘上 – 这可能是在电池供电的系统上,现代操作系统一直在将过时的RAM溢出到磁盘以使hibernate更快。 如果它不再存在于RAM中,操作系统将处理页面错误并为您读取数据。
-
你把它写到文件中。 它返回磁盘,位于不同的位置。
因此数据会从磁盘往返磁盘。 这可能不是你想要的。
您可以通过三种方式处理它。
-
不要使用系统范围的页面文件,而是让操作系统将您的文件用作页面文件。 你可以通过内存映射你的文件,然后简单地写入内存。 关闭映射时,可以保证所有内存页最终都在文件中。 没有涉及往返。
-
有两个线程和一组互锁缓冲区。 一个线程填充缓冲区,另一个线程将它们转储到磁盘。 联锁防止两个线程踩到其他人的脚趾上。 这使您可以使用阻塞调用,如果您对winapi不太熟悉,可能更容易处理。
-
有一个线程但使用非阻塞I / O. 这样你就可以“写”到磁盘而无需等待数据实际到达那里。 有图书馆可以帮助你, 提升可能是一个不错的选择。
我可能会遗漏一些东西,但对我来说,在fread和fwrite耗尽气体之后的明显选择是使用(最初的Win32)函数集CreateFile,ReadFile,WriteFile和CloseHandle。 它们的function更强大,我假设/猜测你使用的f函数是它们周围的包装器。
由于他们更有能力,他们有点难以学习,但嘿,文件I / O不是火箭科学。 如果您使用一组I / O函数实现了代码,那么您将不会失去使用这些函数的方法。