web-dev-qa-db-ja.com

C ++で巨大なファイルを読み取る方法

巨大なファイルがある場合(例:1TB、またはRAMに収まらないサイズ。ファイルはディスクに保存されます)。スペースで区切られています。そして、私のRAMはわずか8GBです。そのファイルをifstreamで読み取ることはできますか?できない場合、ファイルのブロック(例:4GB)を読み取る方法は?

13
ZigZagZebra

できることがいくつかあります。

まず、お持ちのRAMの量よりも大きいファイルを開くことに問題はありません。ファイル全体をコピーすることはできませんliveをメモリに格納します。最良のことは、一度に数個のチャンクのみを読み取って処理する方法を見つけることです。ifstreamを使用して、その目的(- ifstream.read など)。たとえば、1メガバイトのメモリを割り当て、そのファイルの最初のメガバイトをそのメモリに読み込み、すすぎ、繰り返します。

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
}

別の解決策は、ファイルをメモリにマップすることです。ほとんどのオペレーティングシステムでは、物理的なメモリ容量よりも大きい場合でも、ファイルをメモリにマップできます。これは、オペレーティングシステムが、ファイルに関連付けられた各メモリページをオンデマンドでマップおよびマップ解除できることを認識しているために機能します。プログラムが特定のページを必要とする場合、OSはファイルからプロセスのメモリにページを読み取り、ページをスワップアウトします。しばらく使用されていません。

ただし、これが機能するのは、ファイルがプロセスが理論的に使用できるメモリの最大量よりも小さい場合のみです。これは64ビットプロセスの1TBファイルの問題ではありませんが、32ビットプロセスでは機能しません。

また あなたが召喚している霊に注意してください 。ファイルのメモリマッピングは、ファイルの読み取りと同じではありません。ファイルが別のプログラムから突然切り捨てられた場合、プログラムがクラッシュする可能性があります。データを変更すると、ディスクに保存できない場合にメモリが不足する可能性があります。また、メモリをページインおよびページアウトするためのオペレーティングシステムのアルゴリズムは、大幅に有利になるような動作をしない場合があります。これらの不確実性のため、最初のソリューションを使用してチャンクで読み取ることができない場合にのみ、ファイルのマッピングを検討します。

Linux/OS Xでは、mmapを使用します。 Windowsでは、ファイルを開いてからCreateFileMapping、次にMapViewOfFileを使用します。

15
zneak

私はあなたがすべてのファイルをメモリに保持する必要がないと確信しています。通常、チャンクでファイルを読み取って処理する必要があります。 ifstreamを使用したい場合は、次のようにすることができます。

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

より進歩したアプローチは、ファイル全体またはそのチャンクをメモリに読み込む代わりに、プラットフォーム固有のAPIを使用してメモリにマップすることです。

ウィンドウの下:CreateFileMapping()、MapViewOfFile()

Linuxの場合:open(2)/ creat(2)、shm_open、mmap

あなたはそれを動作させるために64ビットアプリをコンパイルする必要があります。

詳細については、こちらを参照してください: CreateFileMapping、MapViewOfFile、システムメモリの保持を回避する方法

2
marcinj