傳統檔案 I/O 需手動管理緩衝區、分段讀寫、處理邊界條件,極易出錯。Win32 記憶體對應檔案將檔案直接映射至進程位址空間,讓檔案操作如同記憶體讀寫般簡單,並天然支援大檔案與進程間資料共享。本文詳細說明映射流程、核心 API、保護屬性,並提供 MASM 範例實作開啟/另存新檔完整功能。
CreateFile 開啟檔案 → 取得檔案控制碼CreateFileMapping 建立檔案映射物件 → 取得映射控制碼MapViewOfFile 映射檔案區域(或整個檔案)至位址空間 → 返回基址指標UnmapViewOfFile 解除映射CloseHandle 關閉映射控制碼與檔案控制碼CreateFileMapping proto hFile:DWORD,
lpFileMappingAttributes:DWORD,
flProtect:DWORD,
dwMaximumSizeHigh:DWORD,
dwMaximumSizeLow:DWORD,
lpName:DWORD
flProtect:PAGE_READONLY/PAGE_READWRITE/PAGE_WRITECOPY 等,必須與 CreateFile 權限相容dwMaximumSizeHigh/Low:映射大小,0,0 表映射整個檔案;指定大於檔案尺寸可擴展檔案lpName:跨進程共享時指定名稱,否則 NULLMapViewOfFile proto hFileMappingObject:DWORD,
dwDesiredAccess:DWORD,
dwFileOffsetHigh:DWORD,
dwFileOffsetLow:DWORD,
dwNumberOfBytesToMap:DWORD
dwDesiredAccess:FILE_MAP_READ/FILE_MAP_WRITE/FILE_MAP_COPY/FILE_MAP_ALL_ACCESSdwFileOffsetHigh/Low:檔案偏移量(64 位元),必須為系統配置粒度倍數(通常 64KB)dwNumberOfBytesToMap:0 表從偏移處映射至檔案結尾功能:Open 對話框開啟檔案 → 映射整個檔案 → 視窗標題顯示檔名 → Save 對話框另存新檔 → WriteFile 將映射記憶體寫入新檔案。全程無 GlobalAlloc 手動記憶體管理。
.if ax==IDM_OPEN
mov ofn.Flags, OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_LONGNAMES|OFN_EXPLORER|OFN_HIDEREADONLY
invoke GetOpenFileName, ADDR ofn
.if eax==TRUE
invoke CreateFile, ADDR buffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFileRead, eax
invoke CreateFileMapping, hFileRead, NULL, PAGE_READONLY, 0, 0, NULL
mov hMapFile, eax
; 視窗標題顯示純檔名
mov eax, OFFSET buffer
movzx edx, ofn.nFileOffset
add eax, edx
invoke SetWindowText, hWnd, eax
invoke EnableMenuItem, hMenu, IDM_OPEN, MF_GRAYED
invoke EnableMenuItem, hMenu, IDM_SAVE, MF_ENABLED
.endif
.elseif ax==IDM_SAVE
mov ofn.Flags, OFN_LONGNAMES|OFN_EXPLORER|OFN_HIDEREADONLY
invoke GetSaveFileName, ADDR ofn
.if eax==TRUE
invoke CreateFile, ADDR buffer, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFileWrite, eax
invoke MapViewOfFile, hMapFile, FILE_MAP_READ, 0, 0, 0
mov pMemory, eax
invoke GetFileSize, hFileRead, NULL
invoke WriteFile, hFileWrite, pMemory, eax, ADDR SizeWritten, NULL
invoke UnmapViewOfFile, pMemory
call CloseMapFile
invoke CloseHandle, hFileWrite
invoke SetWindowText, hWnd, ADDR AppName
invoke EnableMenuItem, hMenu, IDM_OPEN, MF_ENABLED
invoke EnableMenuItem, hMenu, IDM_SAVE, MF_GRAYED
.endif
CloseMapFile PROC
invoke CloseHandle, hMapFile
mov hMapFile, 0
invoke CloseHandle, hFileRead
ret
CloseMapFile endp
WM_DESTROY 中檢查 hMapFile!=0 呼叫 CloseMapFile 確保資源釋放。
| 優勢 | 限制 |
|---|---|
| 無需手動緩衝區分配/鎖定/釋放 | 映射建立後大小固定,無法動態調整 |
| 大檔案隨機存取極快(分頁錯誤自動載入) | 檔案增長需預先指定最大尺寸或重新映射 |
| 天然支援進程間共享記憶體(命名映射) | 共享資料需自行同步(Mutex/Event),否則競爭風險 |
| 系統自動管理分頁交換,記憶體壓力小 | 映射檔案佔用虛擬位址空間,32 位程式 2GB 用戶空間易耗盡 |
MapViewOfFile 指定偏移/長度)處理超過位址空間的檔案FlushViewOfFile 強制寫入磁碟PAGE_WRITECOPY 修改不影響原檔,適合暫存編輯記憶體對應檔案是 Win32 最優雅的檔案存取抽象,將檔案 I/O 轉化為記憶體操作,消除緩衝區管理負擔。掌握 CreateFileMapping 保護屬性、MapViewOfFile 偏移對齊要求、資源清理順序,即可輕鬆處理大檔案、實現高效進程間通訊。