傳統 ReadFile/WriteFile 或 MFC CFile 在處理數十 GB 甚至 TB 級檔案時,頻繁的 I/O 呼叫、緩衝區配置與資料拷貝會造成嚴重效能瓶頸。Windows 記憶體對應檔案 將檔案直接映射至進程虛擬位址空間,讓 CPU 以指標方式存取檔案內容,所有分頁管理、預讀、寫回由系統核心自動完成,極大降低開發複雜度並提升吞吐量。本文詳細說明核心 API 流程、關鍵參數設定,並提供一個接收高速資料流並即時寫入磁碟的實戰範例。
CreateFile:建立/開啟檔案核心物件,取得 HANDLE。CreateFileMapping:建立檔案映射物件,指定保護屬性(PAGE_READWRITE 等)與最大尺寸(64-bit,支援 16 EB)。MapViewOfFile:將映射物件的全部或部分映射至進程位址空間,傳回基底指標 LPVOID。memcpy、指標運算等)。UnmapViewOfFile:解除映射視圖。CloseHandle:關閉映射物件與檔案物件。| API | 關鍵參數 | 說明 |
|---|---|---|
| CreateFile | dwDesiredAccess, dwShareMode | 需與後續映射保護屬性一致;FILE_FLAG_SEQUENTIAL_SCAN 可提示系統做循序預讀。 |
| CreateFileMapping | flProtect, dwMaximumSizeHigh/Low | PAGE_READWRITE 需搭配 GENERIC_READ|GENERIC_WRITE;尺寸以 64-bit 指定。 |
| MapViewOfFile | dwFileOffsetHigh/Low, dwNumberOfBytesToMap | 偏移量必須為系統配置粒度(通常 64 KB)整數倍;可分批映射大檔案的不同區段。 |
情境:從硬體埠接收資料,總量約數十 GB,需即時寫入磁碟,且最終檔案大小需精確反映實際接收量(而非預配大小)。
// ----- 初始化:預配 64 MB 映射空間 -----
HANDLE hFile = CreateFile(L"Recv.tmp",
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,
0, 0x4000000, NULL); // 64 MB
CloseHandle(hFile); // 檔案控制代碼可先關閉
SYSTEM_INFO si; GetSystemInfo(&si);
const DWORD granularity = si.dwAllocationGranularity; // 通常 64 KB
const DWORD viewBytes = 1000 * granularity; // 每次映射 ~64 MB
__int64 fileOffset = 0; // 檔案邏輯位移
__int64 nextRemapThreshold = 600 * granularity; // 38 MB 觸發重映射
BYTE* pView = (BYTE*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS,
0, 0, viewBytes);
// ----- 接收迴圈 -----
while (running)
{
DWORD idx = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
if (idx == WAIT_OBJECT_0) // 資料到達事件
{
int nRead = syio_Read(port, pView + fileOffset, queueLen);
fileOffset += nRead;
// 當寫入量超過閾值,重映射下一區塊
if (fileOffset > nextRemapThreshold)
{
UnmapViewOfFile(pView);
DWORD offsetLow = (DWORD)(fileOffset & 0xFFFFFFFF);
DWORD offsetHigh = (DWORD)(fileOffset >> 32);
pView = (BYTE*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS,
offsetHigh, offsetLow, viewBytes);
nextRemapThreshold = fileOffset + 600 * granularity;
}
}
else if (idx == WAIT_OBJECT_0 + 1) // 結束事件
{
break;
}
}
// ----- 收尾:依實際大小建立最終檔案 -----
UnmapViewOfFile(pView);
CloseHandle(hMap);
// 建立最終檔案,大小 = 實際接收位元組數
HANDLE hFinal = CreateFile(L"Recv.dat",
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
HANDLE hFinalMap = CreateFileMapping(hFinal, NULL, PAGE_READWRITE,
(DWORD)(fileOffset >> 32), (DWORD)(fileOffset & 0xFFFFFFFF), NULL);
CloseHandle(hFinal);
BYTE* pFinalView = (BYTE*)MapViewOfFile(hFinalMap, FILE_MAP_ALL_ACCESS,
0, 0, (DWORD)fileOffset);
memcpy(pFinalView, pView, (size_t)fileOffset);
UnmapViewOfFile(pFinalView);
CloseHandle(hFinalMap);
CloseHandle(hMap);
DeleteFile(L"Recv.tmp");
UnmapViewOfFile 釋放不再需要的視圖,維持虛擬位址空間穩定(32 位元程序特別重要)。CreateFileMapping 指定名稱(lpName),另一進程用 OpenFileMapping 即可共享同一塊實體記憶體,實現高效 IPC。實測顯示,對 50 GB 循序寫入:
WriteFile + 8 MB 緩衝區:約 180 秒優勢來源:省去使用者模式緩衝區拷貝、系統自動最佳化分頁寫入順序、CPU 可直接透過指標運算處理資料。
記憶體對應檔案是 Windows 核心提供的強大機制,適用於超大檔案處理、高效能資料記錄、進程間共享記憶體等場景。掌握 CreateFileMapping/MapViewOfFile 的分段映射技巧,即可在 32/64 位元環境下游刃有餘地處理 TB 級資料。