如果我有一个巨大的文件(例如1TB或任何不能容纳在RAM中的大小。该文件存储在磁盘上)。它由空格分隔。而我的RAM只有8GB。我可以使用ifstream读取该文件吗?如果不行,如何读取文件块(例如4GB)?
你可以做一些事情。
首先,打开一个比你的内存大的文件没有问题。你不能做到的是将整个文件实时复制到内存中。最好的方法是找到一种读取每次只读取几块并处理它们的方式。你可以使用 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
}
另一种解决方案是将文件映射到内存中。大多数操作系统即使文件大小超过您拥有的物理内存量,也允许您将文件映射到内存中。这是因为操作系统知道与文件相关联的每个内存页面都可以按需映射和取消映射:当您的程序需要特定页面时,操作系统会将其从文件中读取到进程的内存中,并交换掉已经有一段时间没有使用的页面。
但是,这只适用于文件小于您的进程可以理论上使用的最大内存量的情况。在64位进程中使用1TB文件不是问题,但在32位进程中就行不通了。
此外,请注意您召唤的精神。将文件映射到内存中并不等同于从文件中读取数据。如果文件突然被其他程序截断,您的程序很可能会崩溃。如果您修改了数据,则可能会因为无法保存回磁盘而耗尽内存。此外,您操作系统用于分页内存的算法可能无法以明显优势的方式运行。由于存在这些不确定性,仅当使用第一种解决方案无法工作时,才应考虑将文件映射到内存中。
在Linux/OS X上,您需要使用mmap
。在Windows上,您需要打开一个文件,然后使用CreateFileMapping
,然后使用MapViewOfFile
。
while (bigFile) { bigFile.read(...); ... }
- user2249683bigFile.read()
读取的数据量小于请求的数据量,则nread的数量在bigFile.gcount()
中。我们可以使用这个nread值来索引缓冲区并继续读取循环吗? - daparic我相信您不必将所有文件保存在内存中。通常,人们希望按块读取和处理文件。如果您想使用 ifstream
,您可以这样做:
ifstream is("/path/to/file");
char buf[4096];
do {
is.read(buf, sizeof(buf));
process_chunk(buf, is.gcount());
} while(is);
is.read()
有时只能读取少于4096
字节,这种情况是否可能? - daparicread
可以读取比请求的字节数更少的字节。请参见 https://en.cppreference.com/w/cpp/io/basic_istream/read - Oleg Andriyanovifstream
对象是否仍然正常?我之所以问这个问题,是因为在C语言中,在循环内部发生中断的情况非常普遍,而read
会继续执行。 - daparicfail()
的返回值。此外,如果您关心精确的错误处理和诸如信号中断之类的低级别事项,您可能希望坚持使用 C 和原始的 POSIX read()
—— API 和文档更加清晰和详细。 - Oleg Andriyanovdo...while(is)
相比仅使用while(is)
有什么好处? - starrietFILE * pFile; pFile = fopen ( "myfile.txt" , "rb" );
而myfile.txt不能适应RAM,我仍然可以用这种方式打开它吗? - ZigZagZebra
/dev/null
似乎是一个很好的名称来存储它。 - Oleg Andriyanov