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

Windows 記憶體映射檔:高效檔案 I/O 與進程間通訊實戰

     編輯:關於C語言

前言

記憶體映射檔(Memory-Mapped File,MMF)將檔案內容直接映射至進程虛擬位址空間,讓檔案讀寫如同記憶體操作,極大提升大檔案隨機存取效能,也是 Windows 進程間共享資料的首選機制。

一、核心 API 流程

  1. CreateFile 取得檔案控制代碼
  2. CreateFileMapping 建立映射物件
  3. MapViewOfFile 將映射物件映射到位址空間,取得基址
  4. 直接透過指標讀寫記憶體
  5. FlushViewOfFile / UnmapViewOfFile / CloseHandle 清理

二、範例 1:提升大檔案讀寫效能

#include <Windows.h>
#include <stdio.h>

#define BUFFSIZE 1024
#define FILE_MAP_START 0x28804

int main() {
    HANDLE hFile = CreateFile(TEXT("test.dat"),
        GENERIC_READ | GENERIC_WRITE, 0, NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return 1;

    // 寫入 65535 個整數(約 256 KB)
    DWORD written;
    for (int i = 0; i < 65535; ++i)
        WriteFile(hFile, &i, sizeof(i), &written, NULL);

    // 取得系統配置粒度,對齊映射位址
    SYSTEM_INFO si; GetSystemInfo(&si);
    DWORD gran = si.dwAllocationGranularity;
    DWORD mapStart = (FILE_MAP_START / gran) * gran;
    DWORD viewSize = (FILE_MAP_START % gran) + BUFFSIZE;
    DWORD mapSize  = FILE_MAP_START + BUFFSIZE;
    DWORD delta    = FILE_MAP_START - mapStart;

    HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,
        0, mapSize, NULL);
    if (!hMap) { CloseHandle(hFile); return 1; }

    LPVOID base = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS,
        0, mapStart, viewSize);
    if (!base) { CloseHandle(hMap); CloseHandle(hFile); return 1; }

    // 直接透過指標讀取特定位移的整數
    int* pData = (int*)((BYTE*)base + delta);
    printf("Value at offset: 0x%X\n", *pData);

    // 修改映射區前 32 位元組
    FillMemory(base, 32, 0xFF);
    FlushViewOfFile(base, viewSize); // 強制寫回磁碟

    UnmapViewOfFile(base);
    CloseHandle(hMap);
    CloseHandle(hFile);
    return 0;
}

三、範例 2:命名映射實現進程間通訊 (IPC)

寫入端

#include <Windows.h>
#include <stdio.h>
#include <conio.h>

#define BUFSIZE 256
LPTSTR szName = TEXT("SharedFileMappingObject");
LPTSTR szMsg  = TEXT("進程訊息");

int main(int argc, char* argv[]) {
    HANDLE hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
        PAGE_READWRITE, 0, BUFSIZE, szName);
    if (!hMap) return 1;

    LPTSTR pBuf = (LPTSTR)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, BUFSIZE);
    if (!pBuf) { CloseHandle(hMap); return 1; }

    if (argc == 1)
        CopyMemory(pBuf, szMsg, _tcslen(szMsg) * sizeof(TCHAR));
    else {
        size_t len = min(strlen(argv[1]), BUFSIZE / sizeof(TCHAR));
        CopyMemory(pBuf, argv[1], len);
    }

    printf("資料已寫入共享記憶體,按任意鍵離開...\n");
    _getch();

    UnmapViewOfFile(pBuf);
    CloseHandle(hMap);
    return 0;
}

讀取端

// 同樣開啟同名映射物件
HANDLE hMap = OpenFileMapping(FILE_MAP_READ, FALSE, szName);
LPTSTR pBuf = (LPTSTR)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, BUFSIZE);
_tprintf(TEXT("讀到: %s\n"), pBuf);
UnmapViewOfFile(pBuf);
CloseHandle(hMap);

四、關鍵參數解析

參數說明
dwAllocationGranularity系統記憶體配置粒度(通常 64 KB),映射位移必須對齊
PAGE_READWRITE映射保護屬性,亦可 PAGE_READONLY、PAGE_WRITECOPY
FILE_MAP_ALL_ACCESS映射視圖存取權,對應讀寫
INVALID_HANDLE_VALUE建立「無檔案支援」的共享記憶體(純 IPC)

五、優缺點與適用場景

  • 優點:系統自動分頁管理、大檔案隨機存取極快、天然支援多進程共享
  • 缺點:需處理位址對齊、映射大小固定難動態擴展、跨平台需抽象層
  • 適用:大型資料檔案(GB 級)、高頻共享記憶體 IPC、熱插拔資料熱備
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved