如何在c中读取大文件

新手上路,请多包涵

如果我有一个巨大的文件(例如 1TB,或者任何不适合 RAM 的大小。文件存储在磁盘上)。它由空格分隔。我的内存只有 8GB。我可以在 ifstream 中读取该文件吗?如果没有,如何读取一个文件块(例如 4GB)?

原文由 ZigZagZebra 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

您可以做几件事。

首先,打开大于您拥有的 RAM 量的文件没有问题。您将无法将整个文件 实时 复制到您的内存中。最好的办法是让您找到一种方法,一次只读取几块并处理它们。为此,您可以使用 ifstream (例如,使用 ifstream.read )。分配,比如说,一兆字节的内存,将该文件的第一兆字节读入其中,冲洗并重复:

 ifstream bigFile("mybigfile.dat");
constexpr size_t bufferSize = 1024 * 1024;
unique_ptr<char[]> buffer(new char[bufferSize]);
while (bigFile)
{
    bigFile.read(buffer.get(), bufferSize);
    // process data in buffer
}

另一种解决方案是将文件映射到内存。大多数操作系统都允许您将文件映射到内存,即使它大于您拥有的物理内存量。这是因为操作系统知道与文件关联的每个内存页面都可以按需映射和取消映射:当您的程序需要特定页面时,操作系统会将其从文件中读取到您的进程的内存中并换出一个页面有一段时间没有使用了。

但是,这只有在文件小于您的进程理论上可以使用的最大内存量时才有效。这不是 1TB 文件在 64 位进程中的问题,但在 32 位进程中不起作用。

还要 注意你召唤的灵魂。内存映射文件与读取文件不同。如果文件突然从另一个程序中截断,您的程序可能会崩溃。如果您修改数据,如果您无法保存回磁盘,则可能会耗尽内存。此外,您的操作系统用于调入和调出内存的算法可能不会以显着优势的方式运行。由于这些不确定性,我会考虑仅在使用第一个解决方案分块读取文件不起作用的情况下映射文件。

在 Linux/OS X 上,您可以使用 mmap 。在 Windows 上,您将打开一个文件,然后使用 CreateFileMapping 然后 MapViewOfFile

原文由 zneak 发布,翻译遵循 CC BY-SA 4.0 许可协议

一种更先进的方法是,您可以使用平台特定的 api 将其映射到内存,而不是将整个文件或其块读取到内存:

windows下:CreateFileMapping()、MapViewOfFile()

linux下:open(2)/creat(2)、shm_open、mmap

您需要编译 64 位应用程序才能使其工作。

有关更多详细信息,请参见此处: CreateFileMapping、MapViewOfFile、如何避免占用系统内存

原文由 marcinj 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题