C++读取超大文件的方法

How to read huge file in c++

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

您可以使用fread

char buffer[size];
fread(buffer, size, sizeof(char), fp);

或者,如果你想使用 C++ fstreams,你可以使用 read as buratino 表示。

还要记住,无论文件大小如何,您都可以打开它,我们的想法是打开它并在适合您的 RAM 的卡盘中读取它。

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

在 windows 下:CreateFileMapping()、MapViewOfFile()

在 linux 下:open(2) / creat(2),shm_open,mmap

您需要编译 64 位应用程序才能运行。

有关详细信息,请参阅此处:CreateFileMapping, MapViewOfFile, how to avoid holding up the system memory

您可以做几件事。

首先,打开大于您拥有的 RAM 容量的文件没有问题。您不能做的是将整个文件 live 复制到您的内存中。最好的办法是找到一种方法一次只读取几个块并处理它们。您可以为此目的使用 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
}

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

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

还有be aware of the spirits that you're summoning。 Memory-mapping 文件与读取文件不同。如果该文件突然从另一个程序 t运行cated,您的程序很可能会崩溃。如果修改了数据,如果不能存回磁盘,可能会运行 out of memory。此外,您的操作系统用于内存分页和分页的算法可能不会以对您有显着优势的方式运行。由于这些不确定性,只有在使用第一种解决方案无法按块读取文件时,我才会考虑映射文件。

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

我相信您不必将所有文件都保存在内存中。通常,人们希望按块读取和处理文件。如果你想使用ifstream,你可以这样做:

ifstream is("/path/to/file");
char buf[4096];
do {
    is.read(buf, sizeof(buf));
    process_chunk(buf, is.gcount());
} while(is);