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

Win32 組合語言教程:記憶體對應檔案高效檔案處理

     編輯:組合語言

前言

傳統檔案 I/O 需手動管理緩衝區、分段讀寫、處理邊界條件,極易出錯。Win32 記憶體對應檔案將檔案直接映射至進程位址空間,讓檔案操作如同記憶體讀寫般簡單,並天然支援大檔案與進程間資料共享。本文詳細說明映射流程、核心 API、保護屬性,並提供 MASM 範例實作開啟/另存新檔完整功能。

記憶體對應檔案核心流程

  1. CreateFile 開啟檔案 → 取得檔案控制碼
  2. CreateFileMapping 建立檔案映射物件 → 取得映射控制碼
  3. MapViewOfFile 映射檔案區域(或整個檔案)至位址空間 → 返回基址指標
  4. 直接透過指標讀寫資料
  5. UnmapViewOfFile 解除映射
  6. CloseHandle 關閉映射控制碼與檔案控制碼

關鍵 API 參數詳解

CreateFileMapping

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:跨進程共享時指定名稱,否則 NULL

MapViewOfFile

MapViewOfFile proto hFileMappingObject:DWORD,
                    dwDesiredAccess:DWORD,
                    dwFileOffsetHigh:DWORD,
                    dwFileOffsetLow:DWORD,
                    dwNumberOfBytesToMap:DWORD
  • dwDesiredAccess:FILE_MAP_READ/FILE_MAP_WRITE/FILE_MAP_COPY/FILE_MAP_ALL_ACCESS
  • dwFileOffsetHigh/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 用戶空間易耗盡

進階應用提示

  • PE 載入器:Windows 載入器即使用映射檔案按需載入 DLL/EXE 區段
  • 大檔案處理:分段映射(MapViewOfFile 指定偏移/長度)處理超過位址空間的檔案
  • Write-through:FlushViewOfFile 強制寫入磁碟
  • Copy-on-write:PAGE_WRITECOPY 修改不影響原檔,適合暫存編輯

總結

記憶體對應檔案是 Win32 最優雅的檔案存取抽象,將檔案 I/O 轉化為記憶體操作,消除緩衝區管理負擔。掌握 CreateFileMapping 保護屬性、MapViewOfFile 偏移對齊要求、資源清理順序,即可輕鬆處理大檔案、實現高效進程間通訊。

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