ファイルの途中からメモリマップドファイルのマッピングをする(続き)

ファイルの途中からマッピングをすることで、何ができるかというと、巨大なファイルを少しずつビューをずらしながら全体を見渡せることができるということが挙げられる。

p619.cpp

#include <windows.h>
#include <stdio.h>

__int64 Count0s(void)
{
	// ビューの先頭アドレスは、割り当て単位の倍数でなければならない
	SYSTEM_INFO sinf;
	GetSystemInfo(&sinf);

	// データファイルをオープンする
	HANDLE hFile = CreateFile(
		"C:\\HugeFile.Big",
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_SEQUENTIAL_SCAN,
		NULL);

	// ファイルマッピングオブジェクトを作成する
	HANDLE hFileMapping = CreateFileMapping(
		hFile,
		NULL,
		PAGE_READONLY,
		0,
		0,
		NULL);

	DWORD dwFileSizeHigh;
	__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
	qwFileSize += (((__int64)dwFileSizeHigh) << 32);

	// ファイルオブジェクトハンドルにはもうアクセスする必要はない
	CloseHandle(hFile);

	__int64 qwFileOffset = 0, qwNumOf0s = 0;

	while (qwFileSize > 0) {
		// このビューにマッピングするバイト数を決める
		DWORD dwBytesInBlock = sinf.dwAllocationGranularity;
		if (qwFileSize < sinf.dwAllocationGranularity) {
			dwBytesInBlock = (DWORD)qwFileSize;
		}

		PBYTE pbFile = (PBYTE)MapViewOfFile(
			hFileMapping,
			FILE_MAP_READ,
			(DWORD)(qwFileOffset >> 32),
			(DWORD)(qwFileOffset & 0xFFFFFFFF),
			dwBytesInBlock);

		// このブロックに含まれる0を数える
		for (DWORD dwByte = 0; dwByte < dwBytesInBlock; dwByte++) {
			if (pbFile[dwByte] == 0) {
				qwNumOf0s++;
			}
		}

		// ビューのマッピングを解除する。
		// アドレス空間に複数のビューを配置するのを避ける
		UnmapViewOfFile(pbFile);

		// ファイル内の次のバイトセットにスキップする
		qwFileOffset += dwBytesInBlock;
		qwFileSize -= dwBytesInBlock;
	}

	CloseHandle(hFileMapping);

	return qwNumOf0s;
}

int main()
{
	return printf("%ld\n", Count0s());
}