居然這就是C++記憶體對映檔案?!

dav2100發表於2021-09-09

記憶體對映檔案大家都時不時聽過,但它到底是個什麼?趕緊來看看吧

記憶體對映檔案到底是幹嘛的呢?讓我們先來思考下面幾個問題:

如果您想讀的內容大於系統分配的記憶體塊怎麼辦?如果您想搜尋的字串剛好超過記憶體塊的邊界又該如何處理?對於第一個問題,您也許會說,只要不斷地讀就不解決了嗎。至於第二個問題,您又會說在記憶體塊的邊界處做一些特別的處理,譬如放上一些標誌位就可以了。原理上確實是行得通,但是這隨問題複雜程度加深而顯得非常難以處理。其中的第二個問題是有名的邊界判斷問題,程式中許許多多的錯誤都是由此引起。想一想,如果我們能夠分配一個能夠容納整個檔案的大記憶體塊該多好啊,這樣這兩個問題不都迎刃而解了嗎?是的,WIN32的記憶體對映檔案確實允許我們分配一個裝得下現實中可能存在的足夠大的檔案的記憶體。

#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    /開始
    //獲得檔案控制程式碼
    HANDLE hFile=CreateFile(
        "c:\test.dat",   //檔名
        GENERIC_READ|GENERIC_WRITE, //對檔案進行讀寫操作
        FILE_SHARE_READ|FILE_SHARE_WRITE,
        NULL,     
        OPEN_EXISTING,  //開啟已存在檔案
        FILE_ATTRIBUTE_NORMAL,   
        0);  

    //返回值size_high,size_low分別表示檔案大小的高32位/低32位
    DWORD size_low,size_high;
    size_low= GetFileSize(hFile,&size_high); 

    //建立檔案的記憶體對映檔案。   
    HANDLE hMapFile=CreateFileMapping(  
        hFile,     
        NULL,   
        PAGE_READWRITE,  //對對映檔案進行讀寫
        size_high,    
        size_low,   //這兩個引數共64位,所以支援的最大檔案長度為16EB
        NULL);   
    if(hMapFile==INVALID_HANDLE_VALUE)   
    {   
        AfxMessageBox("Can't create file mapping.Error%d:n",   GetLastError());   
        CloseHandle(hFile);
        return 0;   
    }  

    //把檔案資料對映到程式的地址空間
    void* pvFile=MapViewOfFile(
        hMapFile, 
        FILE_MAP_READ|FILE_MAP_WRITE, 
        0,
        0,
        0);  
    unsigned char *p=(unsigned char*)pvFile; 

    //至此,就獲得了外部檔案test.dat在記憶體地址空間的對映,
    //下面就可以用指標p"折磨"這個檔案了
    CString s;
    p[size_low-1]='!'; 
    p[size_low-2]='X'; //修改該檔案的最後兩個位元組(檔案大小
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    //開始
    //獲得檔案控制程式碼
    HANDLE hFile=CreateFile(
        "c:\test.dat",   //檔名
        GENERIC_READ|GENERIC_WRITE, //對檔案進行讀寫操作
        FILE_SHARE_READ|FILE_SHARE_WRITE,
        NULL,     
        OPEN_EXISTING,  //開啟已存在檔案
        FILE_ATTRIBUTE_NORMAL,   
        0);  

    //返回值size_high,size_low分別表示檔案大小的高32位/低32位
    DWORD size_low,size_high;
    size_low= GetFileSize(hFile,&size_high); 

    //建立檔案的記憶體對映檔案。   
    HANDLE hMapFile=CreateFileMapping(  
        hFile,     
        NULL,   
        PAGE_READWRITE,  //對對映檔案進行讀寫
        size_high,    
        size_low,   //這兩個引數共64位,所以支援的最大檔案長度為16EB
        NULL);   
    if(hMapFile==INVALID_HANDLE_VALUE)   
    {   
        AfxMessageBox("Can't create file mapping.Error%d:n",   GetLastError());   
        CloseHandle(hFile);
        return 0;   
    }  

    //把檔案資料對映到程式的地址空間
    void* pvFile=MapViewOfFile(
        hMapFile, 
        FILE_MAP_READ|FILE_MAP_WRITE, 
        0,
        0,
        0);  
    unsigned char *p=(unsigned char*)pvFile; 

    //至此,就獲得了外部檔案test.dat在記憶體地址空間的對映,
    //下面就可以用指標p"折磨"這個檔案了
    CString s;
    p[size_low-1]='!'; 
    p[size_low-2]='X'; //修改該檔案的最後兩個位元組(檔案大小

往小了說,只要你把這幾個API函式搞定了,一般的記憶體對映問題就可以解決了。。

利用記憶體對映檔案您可以認為作業系統已經為您把檔案全部裝入了記憶體,然後您只要移動檔案指標進行讀寫即可了。這樣您甚至不需要呼叫那些分配、釋放記憶體塊和檔案輸入/輸出的API函式,另外您可以把這用作不同的程式之間共享資料的一種辦法。運用記憶體對映檔案實際上沒有涉及實際的檔案操作,它更象為每個程式保留一個看得見的記憶體空間。

至於把記憶體對映檔案當成程式間共享資料的辦法來用,則要加倍小心,因為您不得不處理資料的同步問題,否則您的應用程式也許很可能得到過時或錯誤的資料甚至崩潰。本課中我們將主要講述記憶體對映檔案,將不涉及程式間的同步。WIN32中的記憶體對映檔案應用非常廣泛,譬如:即使是系統的核心模組—PE格式檔案裝載器也用到了記憶體對映檔案,因為PE格式的檔案並不是一次性載入到記憶體中來的,譬如他它在首次載入時只載入必需載入的部分,而其他部分在用到時再載入,這正好可以利用到記憶體對映檔案的長處。實際中的大多數檔案存取都和PE載入器類似,所以您在處理該類問題時也應該充分利用記憶體對映檔案。

以下介紹如何使用CreateFileMapping,MapViewOfFile建立記憶體對映檔案,如何向記憶體對映檔案中寫入資料,讀取資料。

#include 
#include 

#include 
#include 

#define BAD_POS 0xFFFFFFFF // returned by SetFilePointer and GetFileSize
#define SUCCESS 0
using namespace std;

typedef DWORD mmf_share_mode;
typedef DWORD mmf_access_mode;
typedef DWORD mmf_flags;

int main(){
    cout

記憶體對映檔案本身還是有一些侷限性的,譬如一旦您生成了一個記憶體對映檔案,那麼您在那個會話期間是不能夠改變它的大小的。所以記憶體對映檔案對於只讀檔案和不會影響其大小的檔案操作是非常有用的。當然這並不意味著對於會引起改變其大小的檔案操作就一定不能用記憶體影射檔案的方法,您可以事先估計操作後的檔案的可能大小,然後生成這麼大小一塊的記憶體對映檔案,然後檔案的長度就可以增長到這麼一個大小。

#include 
#include 

#include 
#include 

#define BAD_POS 0xFFFFFFFF // returned by SetFilePointer and GetFileSize
#define SUCCESS 0
using namespace std;

typedef DWORD mmf_share_mode;
typedef DWORD mmf_access_mode;
typedef DWORD mmf_flags;

int main(){
    cout

圖片描述

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4479/viewspace-2802896/,如需轉載,請註明出處,否則將追究法律責任。

相關文章