如果我有一个巨大的文件(例如1TB,或任何不适合RAM的大小。文件存储在磁盘上)。它由空间划分。我的RAM只有8GB。我可以在ifstream中读取该文件吗?如果没有,如何读取文件块(例如4GB)?
答案 0 :(得分:14)
你可以做几件事。
首先,打开一个大于你拥有的RAM量的文件是没有问题的。您将无法将整个文件 live 复制到您的内存中。最好的办法是找到一种方法,一次只读几个块并处理它们。您可以将ifstream
用于此目的(例如,使用JSONArray)。分配一个兆字节的内存,将该文件的第一兆字节读入其中,冲洗并重复:
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
}
另一种解决方案是将文件映射到内存。大多数操作系统都允许您将文件映射到内存,即使它大于您拥有的物理内存量。这是因为操作系统知道与文件关联的每个内存页面都可以按需映射和取消映射:当您的程序需要特定页面时,操作系统会将其从文件中读取到您的进程内存中并交换出一个页面暂时没有使用过。
但是,只有当文件小于理论上可以使用的进程的最大内存量时,才能使用此功能。这不是64位进程中1TB文件的问题,但它不适用于32位进程。
另外ifstream.read
。内存映射文件与从中读取文件不同。如果文件突然从另一个程序中截断,您的程序可能会崩溃。如果修改数据,如果无法保存回磁盘,则可能会耗尽内存。此外,您的操作系统用于分页进出内存的算法可能不会以显着优势的方式运行。由于存在这些不确定性,我会考虑仅在使用第一个解决方案以块为单位读取文件时才能映射文件。
在Linux / OS X上,您可以使用mmap
。在Windows上,您将打开一个文件,然后使用CreateFileMapping
,然后MapViewOfFile
。
答案 1 :(得分:4)
我确信您不必将所有文件保留在内存中。通常,人们希望通过块读取和处理文件。如果您想使用ifstream
,您可以执行以下操作:
ifstream is("/path/to/file");
char buf[4096];
do {
is.read(buf, sizeof(buf));
process_chunk(buf, is.gcount());
} while(is);
答案 2 :(得分:2)
更进步的方法是不是将整个文件或其块读取到内存中,而是使用特定于平台的api将其映射到内存:
在windows下:CreateFileMapping(),MapViewOfFile()
在linux下:open(2)/ creat(2),shm_open,mmap
您需要编译64位应用才能使其正常工作。
有关详细信息,请参阅此处:CreateFileMapping, MapViewOfFile, how to avoid holding up the system memory
答案 3 :(得分:-1)