1. 程式人生 > 其它 >Windows上的檔案對映與記憶體共享

Windows上的檔案對映與記憶體共享

一、概念

檔案對映:將磁碟上的檔案對映入記憶體,所謂對映就是先在記憶體中分配一塊記憶體預備使用,在使用的時候再將檔案載入入記憶體。

記憶體共享:在程序A中開闢一塊記憶體,然後將這塊記憶體對映到程序B中(程序B實際也會開闢一塊記憶體空間),程序A與B訪問它們物理上各自開闢的空間,但是邏輯上是訪問同一塊記憶體。

二、檔案對映

先使用CreateFile或OpenFile開啟檔案,獲得檔案控制代碼,使用CreateFileMapping建立一個檔案對映物件並獲得該物件的控制代碼,使用檔案對映物件的控制代碼呼叫MapViewOfFileEx建立檔案對映檢視並開闢一塊記憶體空間供檔案對映使用(也可以指定分配哪塊記憶體,最後一個引數指定地址即可,也可以為NULL,這樣是作業系統選定分配的地址)。

PS:指定的lpBaseAddress必須是系統記憶體分配粒度的倍數,否則函式會失敗。

使用到的函式,如下

HANDLE CreateFileMappingA(
  [in]           HANDLE                hFile,//開啟的檔案控制代碼
  [in, optional] LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//NULL
  [in]           DWORD                 flProtect,//許可權
  [in]           DWORD                 dwMaximumSizeHigh,//0
  [in]           DWORD                 dwMaximumSizeLow,//buffer大小
  [in, optional] LPCSTR                lpName   //對映物件的名字
);

LPVOID MapViewOfFileEx(
  [in]           HANDLE hFileMappingObject,
  [in]           DWORD  dwDesiredAccess,//許可權
  [in]           DWORD  dwFileOffsetHigh, //0
  [in]           DWORD  dwFileOffsetLow,  //0
  [in]           SIZE_T dwNumberOfBytesToMap,//buffer大小
  [in, optional] LPVOID lpBaseAddress   //指定在地址處分配空間
);

BOOL UnmapViewOfFile(
  [in] LPCVOID lpBaseAddress
);

示例:

int _tmain(void)
{
    HANDLE hMapFile;
    LPCTSTR pBuf;
    DWORD size;

    hMapFile = CreateFileMapping(
         INVALID_HANDLE_VALUE,    // use paging file
         NULL,                    // default security
         PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES,
         0,                       // max. object size
         size,                    // buffer size
         szName);                 // name of mapping object

    pBuf = (LPTSTR) MapViewOfFile(hMapFile,          // handle to map object
         FILE_MAP_ALL_ACCESS | FILE_MAP_LARGE_PAGES, // read/write permission
         0,
         0,
         BUF_SIZE);

    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
}

  我們使用MapViewOfFileEx返回的地址進行讀寫對映進來的檔案,在修改完畢後作業系統不會馬上寫回磁碟上的檔案,呼叫UnmapViewOfFile後會寫回,但是同時會銷燬檢視,所以我們可以使用FlushViewOfFile來進行及時的修改返回。

BOOL FlushViewOfFile(
  [in] LPCVOID lpBaseAddress,
  [in] SIZE_T  dwNumberOfBytesToFlush
);

PS:

通過對映檢視修改檔案時,最後修改時間戳可能不會自動更新。

檔案的對映檢視不能保證與 ReadFile或 WriteFile函式正在訪問的檔案一致。

MapViewOfFileEx可以處理遠端檔案,但它並不能保持它們的連貫性。

三、記憶體共享

當CreateFileMapping中的檔案控制代碼為-1時,則建立的對映物件用於共享記憶體。

一個程序可以使用 DuplicateHandle函式將檔案對映物件控制代碼複製到另一個程序中,或者另一個程序可以使用OpenFileMapping函式按名稱開啟檔案對映物件 。

另一端的程序同樣也需使用MapViewOfFileEx構建檢視,其他的步驟與檔案對映相同。

HANDLE OpenFileMappingW(
  [in] DWORD   dwDesiredAccess,//許可權
  [in] BOOL    bInheritHandle,    //false
  [in] LPCWSTR lpName            //物件名字,與Create的相同
);

要獲取檢視的大小,請使用 VirtualQueryEx函式。

SIZE_T VirtualQueryEx(
  [in]           HANDLE                    hProcess,
  [in, optional] LPCVOID                   lpAddress,
  [out]          PMEMORY_BASIC_INFORMATION lpBuffer,
  [in]           SIZE_T                    dwLength
);

lpAddress指向要查詢的頁面區域的基地址的指標。

lpBuffer指向 MEMORY_BASIC_INFORMATION結構的指標,在該結構中返回有關指定頁面範圍的資訊。