[解決済み] MapViewOfFileを使用した大容量ファイルのマッピング
質問
非常に大きなファイルがあり、それを細かく分割して読み込んで、それぞれの部分を処理する必要があります。MapViewOfFile関数を使用してメモリ内のピースをマッピングしていますが、最初の部分を読み取った後、2番目の部分を読み取ることができません。それは私がそれをマップしようとしているときにスローされます。
char *tmp_buffer = new char[bufferSize];
LPCWSTR input = L"input";
OFSTRUCT tOfStr;
tOfStr.cBytes = sizeof tOfStr;
HANDLE inputFile = (HANDLE)OpenFile(inputFileName, &tOfStr, OF_READ);
HANDLE fileMap = CreateFileMapping(inputFile, NULL, PAGE_READONLY, 0, 0, input);
while (offset < fileSize)
{
long k = 0;
bool cutted = false;
offset -= tempBufferSize;
if (fileSize - offset <= bufferSize)
{
bufferSize = fileSize - offset;
}
char *buffer = new char[bufferSize + tempBufferSize];
for(int i = 0; i < tempBufferSize; i++)
{
buffer[i] = tempBuffer[i];
}
char *tmp_buffer = new char[bufferSize];
LPCWSTR input = L"input";
HANDLE inputFile;
OFSTRUCT tOfStr;
tOfStr.cBytes = sizeof tOfStr;
long long offsetHigh = ((offset >> 32) & 0xFFFFFFFF);
long long offsetLow = (offset & 0xFFFFFFFF);
tmp_buffer = (char *)MapViewOfFile(fileMap, FILE_MAP_READ, (int)offsetHigh, (int)offsetLow, bufferSize);
memcpy(&buffer[tempBufferSize], &tmp_buffer[0], bufferSize);
UnmapViewOfFile(tmp_buffer);
offset += bufferSize;
offsetHigh = ((offset >> 32) & 0xFFFFFFFF);
offsetLow = (offset & 0xFFFFFFFF);
if (offset < fileSize)
{
char *next;
next = (char *)MapViewOfFile(fileMap, FILE_MAP_READ, (int)offsetHigh, (int)offsetLow, 1);
if (next[0] >= '0' && next[0] <= '9')
{
cutted = true;
}
UnmapViewOfFile(next);
}
ostringstream path_stream;
path_stream << tempPath << splitNum;
ProcessChunk(buffer, path_stream.str(), cutted, bufferSize);
delete buffer;
cout << (splitNum + 1) << " file(s) sorted" << endl;
splitNum++;
}
解決方法は?
1つの可能性は、アロケーション粒度の倍数のオフセットを使用していないことです。 MSDNより。
ハイオフセットとローオフセットの組み合わせは、ファイルマッピング内のオフセットを指定する必要があります。また、システムのメモリ割り当て粒度と一致する必要があります。つまり、オフセットは割り当て粒度の倍数でなければなりません。システムのメモリ割り当て粒度を得るには、SYSTEM_INFO構造体のメンバを埋めるGetSystemInfo関数を使用します。
アロケーション粒度の倍数以外でマッピングしようとすると、マッピングに失敗し
GetLastError
が返されます。
ERROR_MAPPED_ALIGNMENT
.
それ以外にも、コードサンプルには多くの問題があり、何をしようとしているのか、どこで間違っているのかが非常にわかりにくくなっています。 最低限、メモリーリークを解決する必要があります。 完全に不要なバッファを確保し、リークさせているようです。 より良い名前を付けることで、実際に何に使われるかが明確になります。
それから、MapViewOfFileの呼び出しにブレークポイントを設定し、渡しているすべてのパラメータ値が正しいかどうかを確認することをお勧めします。 まず、2回目の呼び出しでは、offsetHighは0、offsetLowはbufferSizeであることが期待されます。
さっそく怪しい点がいくつか。
HANDLE inputFile = (HANDLE)OpenFile(inputFileName, &tOfStr, OF_READ);
どのキャストも疑心暗鬼になるはずです。 時には必要な場合もありますが、その理由をきちんと理解してください。 この時点で、あなたが使っている他のすべてのファイルAPIがなぜ
HANDLE
を返し、この関数は
HFILE
. もし
OpenFileのドキュメント
この関数は機能が限られており、推奨できません。新しいアプリケーションを開発する場合は、CreateFile関数を使用してください」とあります。
long long offsetHigh = ((offset >> 32) & 0xFFFFFFFF);
どのようなタイプか
offset
? おそらく、それが
unsigned long long
またはそれと同等です。 ビットシフトするとき、特に右にシフトするときは、符号拡張を避けるためにほとんどの場合符号なし型が必要です。 32ビットの値を32ビット(またはそれ以上)シフトすることは、CやC++では実際には未定義であり、コンパイラがある種の最適化を行うことができるのです。
long long offsetLow = (offset & 0xFFFFFFFF);
この2つの文で、注意しなければならないのは
0xFFFFFFFF
の値です。 キャストもサフィックスもつけていないので、コンパイラがこれをintとして扱うかunsigned intとして扱うか予測するのは難しいかもしれません。 この場合
しかし、それは多くの人にとって明らかではないでしょう。 実際、そうなのだ。
この答えを最初に書いたとき、私はこれを間違えていました。 [
この段落を修正 16-MAY-2017
] ビット演算では、ほとんどの場合、符号なし値を使用することを確認したいものです。
tmp_buffer = (char *)MapViewOfFile(fileMap, FILE_MAP_READ, (int)offsetHigh, (int)offsetLow, bufferSize);
キャスティングしている
offsetHigh
と
offsetLow
から
int
は、符号付きの値です。 APIは実際には
DWORD
は、符号なし値です。 呼び出しの中でキャストするのではなく、私なら
offsetHigh
と
offsetLow
として
DWORD
のように、初期化でキャスティングを行います。
DWORD offsetHigh = static_cast<DWORD>((offset >> 32) & 0xFFFFFFFFul);
DWORD offsetLow = static_cast<DWORD>( offset & 0xFFFFFFFFul);
tmp_buffer = reinterpret_cast<const char *>(MapViewOfFile(fileMap, FILE_MAP_READ, offsetHigh, offsetLow, bufferSize));
これらの修正は、あなたの問題を解決するかもしれないし、しないかもしれません。 不完全なコードサンプルからは、何が起こっているのかを判断することは困難です。
比較できる動作サンプルはこちらです。
// Calls ProcessChunk with each chunk of the file.
void ReadInChunks(const WCHAR *pszFileName) {
// Offsets must be a multiple of the system's allocation granularity. We
// guarantee this by making our view size equal to the allocation granularity.
SYSTEM_INFO sysinfo = {0};
::GetSystemInfo(&sysinfo);
DWORD cbView = sysinfo.dwAllocationGranularity;
HANDLE hfile = ::CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
if (hfile != INVALID_HANDLE_VALUE) {
LARGE_INTEGER file_size = {0};
::GetFileSizeEx(hfile, &file_size);
const unsigned long long cbFile =
static_cast<unsigned long long>(file_size.QuadPart);
HANDLE hmap = ::CreateFileMappingW(hfile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hmap != NULL) {
for (unsigned long long offset = 0; offset < cbFile; offset += cbView) {
DWORD high = static_cast<DWORD>((offset >> 32) & 0xFFFFFFFFul);
DWORD low = static_cast<DWORD>( offset & 0xFFFFFFFFul);
// The last view may be shorter.
if (offset + cbView > cbFile) {
cbView = static_cast<int>(cbFile - offset);
}
const char *pView = static_cast<const char *>(
::MapViewOfFile(hmap, FILE_MAP_READ, high, low, cbView));
if (pView != NULL) {
ProcessChunk(pView, cbView);
}
}
::CloseHandle(hmap);
}
::CloseHandle(hfile);
}
}
関連
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】指定範囲内の乱数で配列を埋める(C++)
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み] CreateFileMapping、MapViewOfFile、ハンドルリーク c++
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み] C++の識別子でアンダースコアを使用する場合のルールについて教えてください。
-
[解決済み] CまたはC++を使用して、ディレクトリ内のファイルのリストを取得するにはどうすればよいですか?
-
[解決済み] C++のヘッダーファイルで#ifndefと#defineが使われているのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ 非推奨の文字列定数から「char*」への変換について
-
[解決済み】識別子 "string "は未定義?
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】抽象クラス型の無効なnew-expression
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】C++の余分な資格エラー