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

VC++ 利用記憶體映射檔案高效處理超大檔案(數十 GB 級)

     編輯:關於VC++

前言:傳統檔案 I/O 的瓶頸

Win32 API 的 CreateFile/ReadFile/WriteFile 與 MFC CFile 適合一般檔案操作,但面對數十 GB 甚至 TB 級海量數據,頻繁的緩衝區分配、資料搬移、磁碟 I/O 會嚴重拖慢效能。

記憶體映射檔案原理

記憶體映射檔案將磁碟檔案直接映射至進程虛擬位址空間,不再需要顯式 I/O 操作:

  • 系統自動管理頁面快取與磁碟同步
  • 省去「讀入緩衝區→處理→寫回磁碟→釋放緩衝區」的來回複製
  • 天然支援多進程共享超大數據區(本機最高效的 IPC 方式之一)

核心 API 串聯:


CreateFile()        // 開啟/建立檔案核心物件
   → CreateFileMapping() // 建立映射物件,指定大小(64位支援16EB)與保護屬性
      → MapViewOfFile()   // 將全部或部分映射至進程位址空間,取得指標
         → 直接操作記憶體指標 (如同操作記憶體陣列)
      → UnmapViewOfFile() // 解除映射
   → CloseHandle()       // 關閉映射物件
→ CloseHandle()           // 關閉檔案物件

關鍵 API 參數詳解

API關鍵參數與注意點
CreateFileMappingflProtect:PAGE_READWRITE 需搭配 GENERIC_READ|GENERIC_WRITE;dwMaximumSizeHigh/Low 組成 64 位大小
MapViewOfFile偏移量 dwFileOffsetHigh/Low 必須為系統配置粒度整數倍 (通常 64KB);Win9x 需一次映射全檔,Win2K 可僅映射所需視圖
FlushViewOfFile強制將修改頁寫回磁碟,確保資料即時持久化

實戰案例:高速資料記錄系統(接收端口數據,實時存檔)

場景

工作執行緒接收海量數據(數十 GB),事件驅動寫入映射檔案,動態擴展視圖。

核心代碼片段


// 初始化:建立 64MB 映射檔案
HANDLE hFile = CreateFile("Recv1.zip", GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0x4000000, NULL);
CloseHandle(hFile);

__int64 qwOffset = 0;
DWORD dwBlock = 1000 * sysInfo.dwAllocationGranularity; // 映射視圖大小
PBYTE pbView = (PBYTE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, dwBlock);

while (bLoop) {
    DWORD ret = WaitForMultipleObjects(2, hEvents, FALSE, INFINITE);
    if (ret == WAIT_OBJECT_0) { // 收到數據事件
        int nRead = syio_Read(port, pbView + qwOffset, queueLen);
        qwOffset += nRead;
        // 寫入超過 60% 時,重新映射下一視圖
        if (qwOffset > threshold) {
            UnmapViewOfFile(pbView);
            pbView = (PBYTE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, (DWORD)(qwOffset>>32), (DWORD)qwOffset, dwBlock);
            threshold = qwOffset + 600 * sysInfo.dwAllocationGranularity;
        }
    } else { // 結束事件
        UnmapViewOfFile(pbView);
        CloseHandle(hMap);
        break;
    }
}

收尾:修正實際檔案大小

映射檔案預設大小(如 30GB)可能大於實際寫入量(如 14GB),需再建立一個「實際大小」的映射檔案,memcpy 複製有效數據,刪除原臨時檔:


HANDLE hFile2 = CreateFile("Recv.zip", ...);
HANDLE hMap2 = CreateFileMapping(hFile2, NULL, PAGE_READWRITE, 0, (DWORD)qwOffset, NULL);
PBYTE pbView2 = (PBYTE)MapViewOfFile(hMap2, FILE_MAP_ALL_ACCESS, 0, 0, qwOffset);
memcpy(pbView2, pbView, qwOffset);
// 釋放資源、刪除臨時檔

結論

實測記憶體映射檔案在超大檔案處理上效能顯著優於傳統 I/O。代碼在 Win98 + VC6.0 編譯通過,適用於 Win2K/XP 及更新系統。

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