2009-08-19 34 views
2

バイナリ比較器を作成するために、CreateFileW関数を使用して2つのファイルのバイナリ内容を読み込もうとしています。しかし、これはファイル全体をメモリにバッファリングさせ、大きな(500MB)ファイルでは問題になります。C++のメモリにファイル全体をバッファリングせずにバイナリファイルを読む

私は、代わりにファイルの一部をバッファリングすることができる他の関数を見てきましたが、これらの関数でバッファがどのように機能するかを具体的に記述したドキュメントは見つかりませんでした。これは多分私は明白なことを見逃している)。

これまでのところ、私が見つけたと思われるものは、ReadFileです。定義可能なバッファがあるようですが、CreateFileWのように、バックグラウンドで実装された別のバッファが存在しないことは完全にはわかりません。

皆さんは、何が良い機能を使用するかについて意見をお持ちですか?

+3

なぜ 'CreateFile'がファイル全体をメモリにバッファリングすると思いますか? –

+1

@pavelは良い点を持っていますCreateFileWはファイル全体をメモリにバッファリングしません。これは、ファイルのハンドルを作成するだけです。ハンドルを使用して、ファイル全体またはファイルの一部(選択内容)を読み取ることができます。 – leeeroy

+0

あなたは正しいです。私が見ていたコードは、手動ですべてをメモリに格納していることに気付きました。したがって、巨大なフットプリントです。だからこれは、レガシーコード、grrを扱うように感じるものです... –

答えて

7

メモリマップファイルを使用してこれを行うことができます。 createFileで開き、createFileMapping、次にMapViewOfFileを使用してデータへのポインタを取得します。

+0

これは私が必要としていたものです、ありがとう! –

1

私はあなたがほしいと思うと信じますMapViewOfFile

5

CreateFileバッファリングの意味がわからない - CreateFileはファイルの内容全体を読み取ることはできません。また、ReadFileを呼び出す前にCreateFileを呼び出す必要があります。 OSは、一部はopportunisticlyキャッシュデータに先行データの読みくださいかもしれないが、それは、ファイルの全体の500メガバイトを読むことはありません

をあなたが本当に何のバッファリングを持たないようにしたい場合は -

ReadFile関数は、あなたがやりたいだろう。 FILE_FLAG_NO_BUFFERINGをCreateFileに渡し、ファイルへのアクセスがボリュームセクタサイズの倍数であることを確認します。私はあなたがこれをしないことを強くお勧めします - システムファイルキャッシュは理由のために存在し、パフォーマンスに役立ちます。メモリ内のファイルをキャッシュすることは、システム全体のメモリ使用量に影響を与えません。

他にも言及したように、メモリマップファイルも使用できます。メモリマップされたファイルとReadFileとの違いは、主にインターフェイスだけです。最終的に、ファイルマネージャは、バッファリングなど、同様の方法で要求を満たすことになります。インターフェイスは少し直感的ですが、発生したエラーが発生すると例外が発生し、それ以外の場合はプログラムがクラッシュする可能性があることに注意してください。

+0

彼は仮想メモリを心配しているかもしれません - 32ビットのアドレス空間では、500 MBのファイルのための十分なスペースがないかもしれません。 RAMに実際にコピーされているかどうかは問題になりません。 –

+0

そうですが、一度に500 MBを読む必要はありません。 – Michael

5

CreateFile()を呼び出すと、それ自体がターゲットファイルの内容をバッファしたり読み込んだりしません。あなたがランダムな部分を読みたい場合は、さらに

DWORD cbRead; 
BYTE buffer[1024]; 
HANDLE hFile = ::CreateFile(filename, 
          GENERIC_READ, 
          FILE_SHARE_READ, 
          NULL, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_NORMAL, 
          NULL); 
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL); 
::CloseHandle(hFile); 

:のCreateFile()を呼び出した後、あなたは、例えば、ファイルの最初のキロバイトを読み取るために、あなたが好きなファイルの一部取得するReadFile()を呼び出す必要があります何回もあなたは、もちろん、呼び出しSetFilePointer()とのReadFile()

DWORD cbRead; 
BYTE buffer[1024]; 
HANDLE hFile = ::CreateFile(filename, 
          GENERIC_READ, 
          FILE_SHARE_READ, 
          NULL, 
          OPEN_EXISTING, 
          FILE_ATTRIBUTE_NORMAL, 
          NULL); 
::SetFilePointer(hFile, 1024 * 1024, NULL, FILE_BEGIN); 
::ReadFile(hFile, sizeof(buffer), &cbRead, NULL); 
::CloseHandle(hFile); 

:あなたは(ReadFile関数を呼び出す前にSetFilePointer()を使用することができるファイルは、)、例えばファイルに1メガバイトを開始する1キロバイトを読むにはファイルが開かれている間にあなたが望むように。 ReadFile()を呼び出すと、ファイルポインタがReadFile()によって最後に読み取られたバイトの直後のバイトに暗黙的に設定されます。

また、使用しているFile Management Functionsのマニュアルを読み、戻り値を適切にチェックして、発生する可能性のあるエラーをトラップする必要があります。

Windowsは、使用可能なシステムメモリを使用して開いているファイルの内容をキャッシュすることができますが、実行中のプログラムによってメモリが必要な場合、このプロセスによってキャッシュされたデータは破棄されます必要であればディスクから再読み込みしてください)。

関連する問題