2

我基本上是C的新手。

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

我使用一个采集板,它将采集的数据存储在 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并使用指向的内存将所有内容存储在 RAM 中rbuffer12

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 字节的尺寸。

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

4

3 回答 3

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。

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

于 2013-09-09T09:09:42.617 回答
2

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

当您将其“写入”文件时,您正在执行的操作是:

  1. 您在缓冲区的开头访问数据。由于该数据非常旧,因此此时可能已将其分页到磁盘。尽管它同时在磁盘上,但它可能仍然在 RAM 中——这可能是在电池供电的系统上,现代操作系统一直在将陈旧的 RAM 溢出到磁盘上以加快休眠速度。如果它不再在 RAM 中,操作系统会处理页面错误并为您读回数据。

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

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

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

  1. 不要使用系统范围的页面文件,而是让操作系统将您的文件用作页面文件。您可以通过对文件进行内存映射,然后简单地写入内存来做到这一点。当您关闭映射时,您可以保证所有内存页面都在您的文件中。不涉及往返。

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

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

于 2013-09-09T12:24:41.470 回答
0

我可能遗漏了一些东西,但对我来说,在 fread 和 fwrite 用尽 gas 之后,显而易见的选择是使用(最初是 Win32)函数集 CreateFile、ReadFile、WriteFile 和 CloseHandle。它们的功能要强大得多,我假设/猜测您使用的 f 函数是它们的包装器。

因为他们更有能力,所以他们更难学习,但是,文件 I/O 不是火箭科学。如果您已经使用一组 I/O 功能实现了代码,那么您将不会迷失使用这些实现的方式。

于 2013-09-09T14:38:47.293 回答