傳統檔案 I/O 需 CreateFile → SetFilePointer → ReadFile/WriteFile → CloseHandle 多步驟。Windows 提供記憶體對應檔案機制,將檔案直接映射至進程虛擬位址空間,讀寫記憶體即等同讀寫檔案,由系統自動處理分頁、快取、同步寫入。本文示範完整流程:CreateFile → CreateFileMapping → MapViewOfFile → 記憶體操作 → UnmapViewOfFile → CloseHandle,並說明檔案大小擴展技巧。
CreateFile 開啟檔案,取得 HANDLE (GENERIC_READ | GENERIC_WRITE)。CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL) 建立檔案映射物件,0,0 表示映射整個檔案 (大小依檔案實際大小)。MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0) 將映射視圖對應至位址空間,傳回基址指標 (LPVOID)。MOV、STRCPY、MEMCPY),系統自動同步至磁碟。UnmapViewOfFile(pBase) 解除映射視圖。CloseHandle(hMap) 關閉映射物件控制代碼。CloseHandle(hFile) 關閉檔案控制代碼。
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include kernel32.inc
IncludeLib kernel32.lib
ModifyFile PROTO :LPSTR
.data
MyFile db 'd:\masm7\MyTest',0 ; 目標檔案必須預先存在
M1 db 'Good morning',0 ; 寫入位置 0
M2 db 'Good afternoon',0 ; 寫入位置 40h (64 位元組)
M3 db 'Good evening',0 ; 寫入位置 240h (576 位元組)
.data?
hFile dd ?
hMap dd ?
pMapAddr dd ?
.code
START:
invoke CreateFile, ADDR MyFile, \
GENERIC_READ or GENERIC_WRITE, \
FILE_SHARE_READ or FILE_SHARE_WRITE, \
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
.IF eax != INVALID_HANDLE_VALUE
mov hFile, eax
invoke CreateFileMapping, hFile, NULL, PAGE_READWRITE, 0, 0, NULL
.IF eax != NULL
mov hMap, eax
invoke MapViewOfFile, hMap, FILE_MAP_WRITE, 0, 0, NULL
.IF eax != NULL
mov pMapAddr, eax
invoke ModifyFile, pMapAddr
invoke UnmapViewOfFile, pMapAddr
.ENDIF
invoke CloseHandle, hMap
.ENDIF
invoke CloseHandle, hFile
.ENDIF
invoke ExitProcess, 0
ModifyFile proc uses ebx esi edi, lpBufferAddress:LPSTR
mov edi, lpBufferAddress
invoke lstrcpy, edi, ADDR M1 ; Offset 0
add edi, 40h
invoke lstrcpy, edi, ADDR M2 ; Offset 64
add edi, 240h
invoke lstrcpy, edi, ADDR M3 ; Offset 576
ret
ModifyFile endp
END START
| API | 關鍵參數 | 說明 |
|---|---|---|
| CreateFileMapping | hFile, NULL, PAGE_READWRITE, 0, 0, NULL | 高/低 32 位最大尺寸皆為 0 → 映射完整檔案;PAGE_READWRITE 允許讀寫。 |
| MapViewOfFile | hMap, FILE_MAP_WRITE, 0, 0, 0 | 從映射起始 (0,0) 映射整個視圖,FILE_MAP_WRITE 可寫入。 |
| 檔案大小 | CreateFileMapping 的第 4/5 參數 | 指定非 0 值可建立比原檔案大的映射,系統自動擴展檔案 (如第 4 參數=0, 第 5 參數=100h → 擴展至 256 位元組)。 |
原始碼註解記錄的實驗結果:
0,0 → 映射大小 = 原檔案大小。寫入超過原大小的位置 (如 Offset 240h+、576 位元組) 不生效 (範例中 M3 寫入無效)。100h (256 位元組) → 執行後檔案變為 256 位元組,M3 生效。200h (512 位元組) 並屏蔽 UnmapViewOfFile → 檔案變為 512 位元組。UnmapViewOfFile 前呼叫 SetFilePointer(hFile, 新大小, NULL, FILE_BEGIN) + SetEndOfFile(hFile)。| 特性 | 傳統 ReadFile/WriteFile | 記憶體對應檔案 |
|---|---|---|
| 程式碼複雜度 | 高 (指標移動、緩衝區管理) | 低 (直接記憶體操作) |
| 大檔案效能 | 需分塊讀寫 | 系統自動分頁、預讀、快取,極高效 |
| 隨機存取 | 頻繁 SetFilePointer | 直接指標運算,O(1) |
| 多進程共享 | 需鎖定機制 | 同一映射物件天然共享,需同步物件 |
| 檔案擴展/截斷 | SetEndOfFile 直觀 | 需配合 CreateFileMapping 尺寸參數或 SetFilePointer+SetEndOfFile |
| 記憶體佔用 | 僅緩衝區大小 | 佔用虛擬位址空間 (大檔案需注意 32 位進程 2GB 限制) |
CreateFileMapping(..., "Global\\MySharedMem")) 實現高速共享記憶體。MapViewOfFile (指定 Offset/Length)。FlushViewOfFile。FILE_SHARE_READ/WRITE)。INVALID_HANDLE_VALUE, NULL) 並釋放已獲取資源。記憶體對應檔案是 Windows 系統程式設計的強大工具,將檔案 I/O 轉化為記憶體操作,大幅簡化程式碼並提升大檔案處理效能。掌握 CreateFileMapping/MapViewOfFile 核心流程、檔案大小控制技巧、資源釋放順序,即可在組語中靈活運用此機制。