首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

Win32 組語實作:記憶體對應檔案修改檔案內容

     編輯:組合語言

前言

傳統檔案 I/O 需 CreateFile → SetFilePointer → ReadFile/WriteFile → CloseHandle 多步驟。Windows 提供記憶體對應檔案機制,將檔案直接映射至進程虛擬位址空間,讀寫記憶體即等同讀寫檔案,由系統自動處理分頁、快取、同步寫入。本文示範完整流程:CreateFile → CreateFileMapping → MapViewOfFile → 記憶體操作 → UnmapViewOfFile → CloseHandle,並說明檔案大小擴展技巧。

核心 API 流程

  1. CreateFile 開啟檔案,取得 HANDLE (GENERIC_READ | GENERIC_WRITE)。
  2. CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL) 建立檔案映射物件,0,0 表示映射整個檔案 (大小依檔案實際大小)。
  3. MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0) 將映射視圖對應至位址空間,傳回基址指標 (LPVOID)。
  4. 直接透過指標讀寫記憶體 (如 MOV、STRCPY、MEMCPY),系統自動同步至磁碟。
  5. UnmapViewOfFile(pBase) 解除映射視圖。
  6. CloseHandle(hMap) 關閉映射物件控制代碼。
  7. 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關鍵參數說明
CreateFileMappinghFile, NULL, PAGE_READWRITE, 0, 0, NULL高/低 32 位最大尺寸皆為 0 → 映射完整檔案;PAGE_READWRITE 允許讀寫。
MapViewOfFilehMap, 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 寫入無效)。
  • 將第 5 參數 (低 32 位最大尺寸) 設為 100h (256 位元組) → 執行後檔案變為 256 位元組,M3 生效。
  • 設為 200h (512 位元組) 並屏蔽 UnmapViewOfFile → 檔案變為 512 位元組。
  • 嘗試縮小檔案 (改回 80h) → 檔案不縮小,映射機制不支援自動截斷。
  • 真正截斷檔案:需在 UnmapViewOfFile 前呼叫 SetFilePointer(hFile, 新大小, NULL, FILE_BEGIN) + SetEndOfFile(hFile)。

優缺點比較

特性傳統 ReadFile/WriteFile記憶體對應檔案
程式碼複雜度高 (指標移動、緩衝區管理)低 (直接記憶體操作)
大檔案效能需分塊讀寫系統自動分頁、預讀、快取,極高效
隨機存取頻繁 SetFilePointer直接指標運算,O(1)
多進程共享需鎖定機制同一映射物件天然共享,需同步物件
檔案擴展/截斷SetEndOfFile 直觀需配合 CreateFileMapping 尺寸參數或 SetFilePointer+SetEndOfFile
記憶體佔用僅緩衝區大小佔用虛擬位址空間 (大檔案需注意 32 位進程 2GB 限制)

適用情境

  • 大型檔案隨機讀寫:資料庫、影像處理、記憶體映射 I/O (mmap 風格)。
  • 進程間通訊 (IPC):命名映射物件 (CreateFileMapping(..., "Global\\MySharedMem")) 實現高速共享記憶體。
  • 簡化文字/二進位檔案修補:如範例所示,直接字串複製即可完成修改。

注意事項

  • 32 位進程虛擬位址空間 2GB (或 3GB /3GB switch),映射超大檔案需分段 MapViewOfFile (指定 Offset/Length)。
  • 寫入映射視圖不會立即寫入磁碟,由系統延遲寫入 (Lazy Writer);需確保資料持久化可呼叫 FlushViewOfFile。
  • 檔案在映射期間不可被其他程式獨佔開啟 (需 FILE_SHARE_READ/WRITE)。
  • 錯誤處理:每步檢查回傳值 (INVALID_HANDLE_VALUE, NULL) 並釋放已獲取資源。

總結

記憶體對應檔案是 Windows 系統程式設計的強大工具,將檔案 I/O 轉化為記憶體操作,大幅簡化程式碼並提升大檔案處理效能。掌握 CreateFileMapping/MapViewOfFile 核心流程、檔案大小控制技巧、資源釋放順序,即可在組語中靈活運用此機制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved