Win32 API 的 CreateFile/ReadFile/WriteFile 與 MFC CFile 適合一般檔案操作,但面對數十 GB 甚至 TB 級海量數據,頻繁的緩衝區分配、資料搬移、磁碟 I/O 會嚴重拖慢效能。
記憶體映射檔案將磁碟檔案直接映射至進程虛擬位址空間,不再需要顯式 I/O 操作:
核心 API 串聯:
CreateFile() // 開啟/建立檔案核心物件
→ CreateFileMapping() // 建立映射物件,指定大小(64位支援16EB)與保護屬性
→ MapViewOfFile() // 將全部或部分映射至進程位址空間,取得指標
→ 直接操作記憶體指標 (如同操作記憶體陣列)
→ UnmapViewOfFile() // 解除映射
→ CloseHandle() // 關閉映射物件
→ CloseHandle() // 關閉檔案物件
| API | 關鍵參數與注意點 |
|---|---|
CreateFileMapping | flProtect:PAGE_READWRITE 需搭配 GENERIC_READ|GENERIC_WRITE;dwMaximumSizeHigh/Low 組成 64 位大小 |
MapViewOfFile | 偏移量 dwFileOffsetHigh/Low 必須為系統配置粒度整數倍 (通常 64KB);Win9x 需一次映射全檔,Win2K 可僅映射所需視圖 |
FlushViewOfFile | 強制將修改頁寫回磁碟,確保資料即時持久化 |
工作執行緒接收海量數據(數十 GB),事件驅動寫入映射檔案,動態擴展視圖。
// 初始化:建立 64MB 映射檔案
HANDLE hFile = CreateFile("Recv1.zip", GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0x4000000, NULL);
CloseHandle(hFile);
__int64 qwOffset = 0;
DWORD dwBlock = 1000 * sysInfo.dwAllocationGranularity; // 映射視圖大小
PBYTE pbView = (PBYTE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, dwBlock);
while (bLoop) {
DWORD ret = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
if (ret == WAIT_OBJECT_0) { // 收到數據事件
int nRead = syio_Read(port, pbView + qwOffset, queueLen);
qwOffset += nRead;
// 寫入超過 60% 時,重新映射下一視圖
if (qwOffset > threshold) {
UnmapViewOfFile(pbView);
pbView = (PBYTE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, (DWORD)(qwOffset>>32), (DWORD)qwOffset, dwBlock);
threshold = qwOffset + 600 * sysInfo.dwAllocationGranularity;
}
} else { // 結束事件
UnmapViewOfFile(pbView);
CloseHandle(hMap);
break;
}
}
映射檔案預設大小(如 30GB)可能大於實際寫入量(如 14GB),需再建立一個「實際大小」的映射檔案,memcpy 複製有效數據,刪除原臨時檔:
HANDLE hFile2 = CreateFile("Recv.zip", ...);
HANDLE hMap2 = CreateFileMapping(hFile2, NULL, PAGE_READWRITE, 0, (DWORD)qwOffset, NULL);
PBYTE pbView2 = (PBYTE)MapViewOfFile(hMap2, FILE_MAP_ALL_ACCESS, 0, 0, qwOffset);
memcpy(pbView2, pbView, qwOffset);
// 釋放資源、刪除臨時檔
實測記憶體映射檔案在超大檔案處理上效能顯著優於傳統 I/O。代碼在 Win98 + VC6.0 編譯通過,適用於 Win2K/XP 及更新系統。