• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            內存映射修改大文件

            http://www.vckbase.com/document/viewdoc/?id=1831

            下載源代碼

            本文介紹利用內存映射文件修改大文件:在大文件內存前加入一段數據,若要使用內存映射文件,必須執行下列操作步驟:

            1. 創建或打開一個文件內核對象,該對象用于標識磁盤上你想用作內存映射文件的文件;
            2. 創建一個文件映射內核對象,告訴系統該文件的大小和你打算如何訪問該文件;
            3. 讓系統將文件映射對象的全部或一部分映射到你的進程地址空間中;

            當完成對內存映射文件的使用時,必須執行下面這些步驟將它清除:

            1. 告訴系統從你的進程的地址空間中撤消文件映射內核對象的映像;
            2. 關閉文件映射內核對象;
            3. 關閉文件內核對象;

              下面將用一個實例詳細介紹這些操作步驟,(本實例的目的就是將一個文件A其內容前面加入一些內容存入文件B,我想大家在程序開發當中會遇到這種情況的)

            一、我們打開關于A文件內核對象,并創建一個關于B文件的內核對象

            若要創建或打開一個文件內核對象,總是要調用CreateFile函數:

            HANDLE CreateFile(
            PCSTR pszFileName,
            DWORD dwDesiredAccess,
            DWORD dwShareMode,
            PSECURITY_ATTRIBUTES psa,
            DWORD dwCreationDisposition,
            DWORD dwFlagsAndAttributes,
            HANDLE hTemplateFile);

            CreateFile函數擁有好幾個參數,這里只重點介紹前3個參數,即pszFileName,dwDesiredAccessdwShareMode

            你可能會猜到,第一個參數pszFileName用于指明要創建或打開的文件的名字(包括一個選項路徑),第二個參數dwDesiredAccess用于設定如何訪問該文件的內容,可以設定下表所列的4個值中的一個。

            含義

            0

            不能讀取或寫入文件的內容,當只想獲得文件的屬性時,請設定0

            GENERIC_READ

            可以從文件中讀取數據

            GENERIC_WRITE

            可以將數據寫入文件

            GENERIC_READ|GENERIC_WRITE

            可以從文件中讀取數據,也可以將數據寫入文件

              當創建或打開一個文件,將它作為一個內存映射文件來使用時,請選定最有意義的一個或多個訪問標志,以說明你打算如何訪問文件的數據,對內存映射文件來說,必須打開用于只讀訪問或讀寫訪問的文件,因此,可以分別設定GENERIC_READGENERIC_READ|GENERIC_WRITE,

            第三個參數dwShareMode告訴系統你想如何共享該文件,可以為dwShareMode設定下表所列的4個值之一:
             

            含義

            0

            打開文件的任何嘗試均將失敗

            FILE_SHARE_READ

            使用GENERIC_WRITE打開文件的其他嘗試將會失敗

            FILE_SHARE_WRITE

            使用GENERIC_READ打開文件的其他嘗試將會失敗

            FILE_SHARE_READFILE_SHARE_WRITE

            打開文件的其他嘗試將會取得成功

            如果CreateFile函數成功地創建或打開指定的文件,便返回一個文件內核對象的句柄,否則返回INVALID_HANDLE_VALUE,

            注意能夠返回句柄的大多數Windows函數如果運行失敗,那么就會返回NULL,但是,CreateFile函數將返回INVALID_HANDLE_VALUE,它定義為((HANDLE)-1),

            HANDLEhFile=CreateFile(.\\first.txt,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
            HANDLEhmyfile=CreateFile(E:\\my.txt,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

            二、我們要分別創建兩個文件映射內核對象

              調用CreateFile函數,就可以將文件映像的物理存儲器的位置告訴操作系統,你傳遞的路徑名用于指明支持文件映像的物理存儲器在磁盤(或網絡或光盤)上的確切位置,這時,必須告訴系統,文件映射對象需要多少物理存儲器,若要進行這項操作,可以調用CreateFileMapping函數:

            HANDLE CreateFileMapping(
            HANDLE hFile,
            PSECURITY_ATTRIBUTES psa,
            DWORD fdwProtect,
            DWORD dwMaximumSizeHigh,
            DWORD dwMaximumSizeLow,
            PCTSTR pszName);

            第一個參數hFile用于標識你想要映射到進程地址空間中的文件句柄,該句柄由前面調用的CreateFile函數返回,psa參數是指向文件映射內核對象的SECURITY_ATTRIBUTES結構的指針,通常傳遞的值是NULL(它提供默認的安全特性,返回的句柄是不能繼承的)
              本章開頭講過,創建內存映射文件就像保留一個地址空間區域然后將物理存儲器提交給該區域一樣,因為內存映射文件的物理存儲器來自磁盤上的一個文件,而不是來自從系統的頁文件中分配的空間,當創建一個文件映射對象時,系統并不為它保留地址空間區域,也不將文件的存儲器映射到該區域(下一節將介紹如何進行這項操作),但是,當系統將存儲器映射到進程的地址空間中去時,系統必須知道應該將什么保護屬性賦予物理存儲器的頁面,CreateFileMapping函數的fdwProtect參數使你能夠設定這些保護屬性,大多數情況下,可以設定下表中列出的3個保護屬性之一。

            使用fdwProtect參數設定的部分保護屬性

            保護屬性

            含義

            PAGE_READONLY

            當文件映射對象被映射時,可以讀取文件的數據,必須已經將GENERIC_READ傳遞給CreateFile函數。

            PAGE_READWRITE

            當文件映射對象被映射時,可以讀取和寫入文件的數據,必須已經將GENERIC_READ|GENERIC_WRITE傳遞給CreateFile

            PAGE_WRITECOPY

            當文件映射對象被映射時,可以讀取和寫入文件的數據,如果寫入數據,會導致頁面的私有拷貝得以創建,必須已經將GENERIC_READGENERIC_WRITE傳遞給CreateFile

              在Windows98,可以將PAGE_WRITECOPY標志傳遞給CreateFileMapping,這將告訴系統從頁文件中提交存儲器,該頁文件存儲器是為數據文件的數據拷貝保留的,只有修改過的頁面才被寫入頁文件,你對該文件的數據所作的任何修改都不會重新填入原始數據文件,其最終結果是,PAGE_WRITECOPY標志的作用在Windows2000Windows98上是相同的。
              除了上面的頁面保護屬性外,還有4個節保護屬性,你可以用OR將它們連接起來放入CreateFileMapping函數的fdwProtect參數中,節只是用于內存映射的另一個術語。
              節的第一個保護屬性是SEC_NOCACHE,它告訴系統,沒有將文件的任何內存映射頁面放入高速緩存,因此,當將數據寫入該文件時,系統將更加經常地更新磁盤上的文件數據,這個標志與PAGE_NOCACHE保護屬性標志一樣,是供設備驅動程序開發人員使用的,應用程序通常不使用,

            Windows98將忽略SEC_NOCACHE標志。

              節的第二個保護屬性是SEC_IMAGE,它告訴系統,你映射的文件是個可移植的可執行(PE)文件映像,當系統將該文件映射到你的進程的地址空間中時,系統要查看文件的內容,以確定將哪些保護屬性賦予文件映像的各個頁面,例如,PE文件的代碼節(.text)通常用PAGE_EXECUTE_READ屬性進行映射,PE文件的數據節(.data)則通常用PAGE_READWRITE屬性進行映射,如果設定的屬性是SEC_IMAGE,則告訴系統進行文件映像的映射,并設置相應的頁面保護屬性。

            Windows98將忽略SEC_IMAGE標志

              最后兩個保護屬性是SEC_RESERVESEC_COMMIT,它們是兩個互斥屬性,當使用內存映射數據文件時,它們不能使用,這兩個標志將在本章后面介紹,當創建內存映射數據文件時,不應該設定這些標志中的任何一個標志,CreateFileMapping將忽略這些標志。
              CreateFileMapping的另外兩個參數是dwMaximumSizeHighdwMaximumSizeLow,它們是兩個最重要的參數,CreateFileMapping函數的主要作用是保證文件映射對象能夠得到足夠的物理存儲器,這兩個參數將告訴系統該文件的最大字節數,它需要兩個32位的值,因為Windows支持的文件大小可以用64位的值來表示,dwMaximumSizeHigh參數用于設定較高的32,dwMaximumSizeLow參數則用于設定較低的32位值,對于4GB或小于4GB的文件來說,dwMaximumSizeHigh的值將始終是0
              使用64位的值,意味著Windows能夠處理最大為16EB(1018字節)的文件,如果想要創建一個文件映射對象,使它能夠反映文件當前的大小,那么可以為上面兩個參數傳遞0,如果只打算讀取該文件或者訪問文件而不改變它的大小,那么為這兩個參數傳遞0,如果打算將數據附加給該文件,可以選擇最大的文件大小,以便為你留出一些富裕的空間,如果當前磁盤上的文件包含0字節,那么可以給CreateFileMapping函數的dwMaximumSizeHighdwMaximumSizeLow傳遞兩個0,這樣做就可以告訴系統,你要的文件映射對象里面的存儲器為0字節,這是個錯誤,CreateFileMapping將返回NULL
              如果你對我們講述的內容一直非常關注,你一定認為這里存在嚴重的問題,Windows支持最大為16EB的文件和文件映射對象,這當然很好,但是,怎樣將這樣大的文件映射到32位進程的地址空間(32位地址空間是4GB文件的上限)中去呢,下一節介紹解決這個問題的辦法,當然,64位進程擁有16EB的地址空間,因此可以進行更大的文件的映射操作,但是,如果文件是個超大規模的文件,仍然會遇到類似的問題。
              若要真正理解CreateFileCreateFileMapping兩個函數是如何運行的,建議你做一個下面的實驗,建立下面的代碼,對它進行編譯,然后在一個調試程序中運行它,當你一步步執行每個語句時,你會跳到一個命令解釋程序,并執行C:\目錄上的“dir”命令,當執行調試程序中的每個語句時,請注意目錄中出現的變化。

            int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE,
               PTSTR pszCmdLine, int nCmdShow)
            {
               //Before executing the line below, C:\ does not have
               //a file called "MMFTest.Dat."
               HANDLE hfile = CreateFile("C:\\MMFTest.dat", 
                  GENERIC_READ | GENERIC_WRITE,
                  FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
                  FILE_ATTRIBUTE_NORMAL, NULL);
             
               //Before executing the line below, the MMFTest.Dat
               //file does exist but has a file size of 0 bytes.
               HANDLE hfilemap = CreateFileMapping(hfile, NULL, PAGE_READWRITE,
                  0, 100, NULL);
             
               //After executing the line above, the MMFTest.Dat
               //file has a size of 100 bytes.
             
               //Cleanup
               CloseHandle(hfilemap);
               CloseHandle(hfile);
             
               //When the process terminates, MMFTest.Dat remains
               //on the disk with a size of 100 bytes.
               return(0);
            }

              如果調用CreateFileMapping函數,傳遞PAGE_READWRITE標志,那么系統將設法確保磁盤上的相關數據文件的大小至少與dwMaximumSizeHighdwMaximumSizeLow參數中設定的大小相同,如果該文件小于設定的大小,CreateFileMapping函數將擴展該文件的大小,使磁盤上的文件變大,這種擴展是必要的,這樣,當以后將該文件作為內存映射文件使用時,物理存儲器就已經存在了,如果正在用PAGE_READONLYPAGE_WRITECOPY標志創建該文件映射對象,那么CreateFileMapping特定的文件大小不得大于磁盤文件的物理大小,這是因為你無法將任何數據附加給該文件。
              CreateFileMapping函數的最后一個參數是pszName,它是個以0結尾的字符串,用于給該文件映射對象賦予一個名字,該名字用于與其他進程共享文件映射對象(本章后面展示了它的一個例子,3章詳細介紹了內核對象的共享操作),內存映射數據文件通常并不需要被共享,因此這個參數通常是NULL
              系統創建文件映射對象,并將用于標識該對象的句柄返回該調用線程,如果系統無法創建文件映射對象,便返回一個NULL句柄值,記住,CreateFile運行失敗時,它將返回INVALID_HANDLE_VALUE(定義為-1),CreateFileMapping運行失敗時,它返回NULL,請不要混淆這些錯誤值。

            在本實例中創建文件映射內核對象代碼如下:

            HANDLE hFileMapping = CreateFileMapping(hFile, NULL, 
                  PAGE_READONLY, 0, 0, NULL);
               DWORD dwFileSizeHigh;
               __int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
               qwFileSize += (((__int64) dwFileSizeHigh) << 32);
               char AddMsg[]="Girl,you love me?, I love you very much!";              //加入的文件內容
             
               __int64 myFilesize=qwFileSize+sinf.dwAllocationGranularity;            //合并后的文件大小
              HANDLE hmyfilemap = CreateFileMapping(hmyfile, NULL, PAGE_READWRITE,   //合并文件大小的內存映射對象
                  (DWORD)(myFilesize>>32), (DWORD)(myFilesize& 0xFFFFFFFF), NULL);

            三、將文件數據映射到地址空間

              當創建了一個文件映射對象后,仍然必須讓系統為文件的數據保留一個地址空間區域,并將文件的數據作為映射到該區域的物理存儲器進行提交,可以通過調用MapViewOfFile函數來進行這項操作:

            PVOID MapViewOfFile(
            HANDLE hFileMappingObject,
            DWORD dwDesiredAccess,
            DWORD dwFileOffsetHigh,
            DWORD dwFileOffsetLow,
            SIZE_T dwNumberOfBytesToMap);

              參數hFileMappingObject用于標識文件映射對象的句柄,該句柄是前面調用CreateFileMappingOpenFileMapping(本章后面介紹)函數返回的,參數dwDesiredAccess用于標識如何訪問該數據,不錯,必須再次設定如何訪問文件的數據,可以設定下表所列的4個值中的一個。

            17-6值及其含義

            含義

            FILE_MAP_WRITE

            可以讀取和寫入文件數據,CreateFileMapping函數必須通過傳遞PAGE_READWRITE標志來調用

            FILE_MAP_READ

            可以讀取文件數據,CreateFileMapping函數可以通過傳遞下列任何一個保護屬性來調用:PAGE_READONLY,PAGE_READWRITEPAGE_WRITECOPY

            FILE_MAP_ALL_ACCESS

            FILE_MAP_WRITE相同

            FILE_MAP_COPY

            可以讀取和寫入文件數據,如果寫入文件數據,可以創建一個頁面的私有拷貝,Windows2000,CreateFileMapping函數可以用PAGE_READONLY,PAGE_READWRITEPAGE_WRITECOPY等保護屬性中的任何一個來調用,Windows98,CreateFileMapping必須用PAGE_WRITECOPY來調用。

              Windows要求所有這些保護屬性一次又一次地重復設置,這當然有些奇怪和煩人,我認為這樣做可以使應用程序更多地對數據保護屬性進行控制,
              剩下的3個參數與保留地址空間區域及將物理存儲器映射到該區域有關,當你將一個文件映射到你的進程的地址空間中時,你不必一次性地映射整個文件,相反,可以只將文件的一小部分映射到地址空間,被映射到進程的地址空間的這部分文件稱為一個視圖,這可以說明MapViewOfFile是如何而得名的,
              當將一個文件視圖映射到進程的地址空間中時,必須規定兩件事情,首先,必須告訴系統,數據文件中的哪個字節應該作為視圖中的第一個字節來映射,你可以使用dwFileOffsetHighdwFileOffsetLow參數來進行這項操作,由于Windows支持的文件最大可達16EB,因此必須用一個64位的值來設定這個字節的位移值,這個64位值中,較高的32位傳遞給參數dwFileOffsetHigh,較低的32位傳遞給參數dwFileOffsetLow,注意,文件中的這個位移值必須是系統的分配粒度的倍數(迄今為止,Windows的所有實現代碼的分配粒度均為64KB),14章介紹了如何獲取某個系統的分配粒度。
              第二,必須告訴系統,數據文件有多少字節要映射到地址空間,這與設定要保留多大的地址空間區域的情況是相同的,可以使用dwNumberOfBytesToMap參數來設定這個值,如果設定的值是0,那么系統將設法把從文件中的指定位移開始到整個文件的結尾的視圖映射到地址空間。
              在Windows98,如果MapViewOfFile無法找到足夠大的區域來存放整個文件映射對象,那么無論需要的視圖是多大,MapViewOfFile均將返回NULL
              在Windows2000,MapViewOfFile只需要為必要的視圖找到足夠大的一個區域,而不管整個文件映射對象是多大。
              如果在調用MapViewOfFile函數時設定了FILE_MAP_COPY標志,系統就會從系統的頁文件中提交物理存儲器,提交的地址空間數量由dwNumberOfBytesToMap參數決定,只要你不進行其他操作,只是從文件的映像視圖中讀取數據,那么系統將決不會使用頁文件中的這些提交的頁面,但是,如果進程中的任何線程將數據寫入文件的映像視圖中的任何內存地址,那么系統將從頁文件中抓取已提交頁面中的一個頁面,將原始數據頁面拷貝到該頁交換文件中,然后將該拷貝的頁面映射到你的進程的地址空間,從這時起,你的進程中的線程就要訪問數據的本地拷貝,不能讀取或修改原始數據。

            當系統制作原始頁面的拷貝時,系統將把頁面的保護屬性從PAGE_WRITECOPY改為PAGE_READWRITE,下面這個代碼段就說明了這個情況:

            // Open the file that we want to map.
            HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
               OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
             
            // Create a file-mapping object for the file.
            HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY,
               0, 0, NULL);
             
            // Map a copy-on-write view of the file; the system will commit
            // enough physical storage from the paging file to accommodate
            // the entire file. All pages in the view will initially have
            // PAGE_WRITECOPY access.
             
            PBYTE pbFile = (PBYTE) MapViewOfFile(hFileMapping, FILE_MAP_COPY,
               0, 0, 0);
             
            // Read a byte from the mapped view.
            BYTE bSomeByte = pbFile[0];
             
            // When reading, the system does not touch the committed pages in
            // the paging file. The page keeps its PAGE_WRITECOPY attribute.
             
            // Write a byte to the mapped view.
            pbFile[0] = 0;
             
            // When writing for the first time, the system grabs a committed
            // page from the paging file, copies the original contents of the
            // page at the accessed memory address, and maps the new page
            // (the copy) into the process's address space. The new page has
            // an attribute of PAGE_READWRITE.
             
            // Write another byte to the mapped view.
            pbFile[1] = 0;
             
            // Because this byte is now in a PAGE_READWRITE page, the system
            // simply writes the byte to the page (backed by the paging file).
             
            // When finished using the file's mapped view, unmap it.
            // UnmapViewOfFile is discussed in the next section.
            UnmapViewOfFile(pbFile);
             
            // The system decommits the physical storage from the paging file.
            // Any writes to the pages are lost.
             
            // Clean up after ourselves.
            CloseHandle(hFileMapping);
            CloseHandle(hFile);

            Windows98前面講過,Windows98必須預先為內存映射文件提交頁文件中的存儲器,然而,它只有在必要時才將修改后的頁面寫入頁文件,

            四、從進程的地址空間撤消文件數據的映射

            當不再需要保留映射到你的進程地址空間區域中的文件數據時,可以通過調用下面的函數將它釋放:

            BOOLUnmapViewOfFile(PVOIDpvBaseAddress);

              該函數的唯一的參數pvBaseAddress用于設定返回區域的基地址,該值必須與調用MapViewOfFile函數返回的值相同,必須記住要調用UnmapViewOfFile函數,如果沒有調用這個函數,那么在你的進程終止運行前,保留的區域就不會被釋放,每當你調用MapViewOfFile,系統總是在你的進程地址空間中保留一個新區域,而以前保留的所有區域將不被釋放。
              為了提高速度,系統將文件的數據頁面進行高速緩存,并且在對文件的映射視圖進行操作時不立即更新文件的磁盤映像,如果需要確保你的更新被寫入磁盤,可以強制系統將修改過的數據的一部分或全部重新寫入磁盤映像中,方法是調用FlushViewOfFile函數:

            BOOLFlushViewOfFile(
            PVOIDpvAddress,
            SIZE_TdwNumberOfBytesToFlush);

              第一個參數是包含在內存映射文件中的視圖的一個字節的地址,該函數將你在這里傳遞的地址圓整為一個頁面邊界值,第二個參數用于指明你想要刷新的字節數,系統將把這個數字向上圓整,使得字節總數是頁面的整數,如果你調用FlushViewOfFile函數并且不修改任何數據,那么該函數只是返回,而不將任何信息寫入磁盤。
              對于存儲器是在網絡上的內存映射文件來說,FlushViewOfFile能夠保證文件的數據已經從工作站寫入存儲器,但是FlushViewOfFile不能保證正在共享文件的服務器已經將數據寫入遠程磁盤,因為服務器也許對文件的數據進行了高速緩存,若要保證服務器寫入文件的數據,每當你為文件創建一個文件映射對象并且映射該文件映射對象的視圖時,應該將FILE_FLAG_WRITE_THROUGH標志傳遞給CreateFile函數,如果你使用該標志打開該文件,那么只有當文件的全部數據已經存放在服務器的磁盤驅動器中的時候,FlushViewOfFile函數才返回。
              記住UnmapViewOfFile函數的一個特殊的特性,如果原先使用FILE_MAP_COPY標志來映射視圖,那么你對文件的數據所作的任何修改,實際上是對存放在系統的頁文件中的文件數據的拷貝所作的修改,在這種情況下,如果調用UnmapViewOfFile函數,該函數在磁盤文件上就沒有什么可以更新,而只會釋放頁文件中的頁面,從而導致數據丟失。
              如果想保留修改后的數據,必須采用別的措施,例如,你可以用同一個文件創建另一個文件映射對象(使用PAGE_READWRITE),然后使用FILE_MAP_WRITE標志將這個新文件映射對象映射到進程的地址空間,之后,你可以掃描第一個視圖,尋找帶有PAGE_READWRITE保護屬性的頁面,每當你找到一個帶有該屬性的頁面時,可以查看它的內容,并且確定是否將修改了的數據寫入該文件,如果不想用新數據更新該文件,那么繼續對視圖中的剩余頁面進行掃描,直到視圖的結尾,但是,如果你確實想要保存修改了的數據頁面,那么只需要調用MoveMemory函數,將數據頁面從第一個視圖拷貝到第二個視圖,由于第二個視圖是用PAGE_READWRITE保護屬性映射的,因此MoveMemory函數將更新磁盤上的實際文件內容,可以使用這種方法來確定文件的變更并保存你的文件的數據。
              Windows98不支持copy-on-write(寫入時拷貝)保護屬性,因此,當掃描內存映射文件的第一個視圖時,無法測試用PAGE_READWRITE標志做上標記的頁面,你必須設計一種方法來確定第一個視圖中的哪些頁面已經做了修改。

            五、關閉文件映射對象和文件對象

              不用說,你總是要關閉你打開了的內核對象,如果忘記關閉,在你的進程繼續運行時會出現資源泄漏的問題,當然,當你的進程終止運行時,系統會自動關閉你的進程已經打開但是忘記關閉的任何對象,但是如果你的進程暫時沒有終止運行,你將會積累許多資源句柄,因此你始終都應該編寫清楚而又正確的代碼,以便關閉你已經打開的任何對象,若要關閉文件映射對象和文件對象,只需要兩次調用CloseHandle函數,每個句柄調用一次:

            讓我們更加仔細地觀察一下這個進程,下面的偽代碼顯示了一個內存映射文件的例子:

            HANDLEhFile=CreateFile(...);
            HANDLEhFileMapping=CreateFileMapping(hFile,...);
            PVOIDpvFile=MapViewOfFile(hFileMapping,...);
             
            //Usethememory-mappedfile.
             
            UnmapViewOfFile(pvFile);
            CloseHandle(hFileMapping);
            CloseHandle(hFile);

              上面的代碼顯示了對內存映射文件進行操作所用的預期方法,但是,它沒有顯示,當你調用MapViewOfFile時系統對文件對象和文件映射對象的使用計數的遞增情況,這個副作用是很大的,因為它意味著我們可以將上面的代碼段重新編寫成下面的樣子:

            HANDLEhFile=CreateFile(...);
            HANDLEhFileMapping=CreateFileMapping(hFile,...);
            CloseHandle(hFile);
            PVOIDpvFile=MapViewOfFile(hFileMapping,...);
            CloseHandle(hFileMapping);
             
            //Usethememory-mappedfile.
             
            UnmapViewOfFile(pvFile);

              當對內存映射文件進行操作時,通常要打開文件,創建文件映射對象,然后使用文件映射對象將文件的數據視圖映射到進程的地址空間,由于系統遞增了文件對象和文件映射對象的內部使用計數,因此可以在你的代碼開始運行時關閉這些對象,以消除資源泄漏的可能性,
            如果用同一個文件來創建更多的文件映射對象,或者映射同一個文件映射對象的多個視圖,那么就不能較早地調用CloseHandle函數——以后你可能還需要使用它們的句柄,以便分別對CreateFileMappingMapViewOfFile函數進行更多的調用,
            本實例中第三到第六步代碼如下:

            CloseHandle(hFile);//Wenolongerneedaccesstothefileobjectshandle.
            CloseHandle(hmyfile);
             
            PBYTEpbmyFile=(PBYTE)MapViewOfFile(hmyfilemap,FILE_MAP_WRITE,//內存映射視圖
            0,//Startingbyte
            0,//infile
            sizeof(AddMsg));
            memcpy(pbmyFile,AddMsg,sizeof(AddMsg));//加入內容
            UnmapViewOfFile(pbmyFile);
             
            __int64qwFileOffset=0;//A文件視圖的偏移量
            __int64qwmyFileOffset=sinf.dwAllocationGranularity;//合并文件視圖的遍移量
             
            while(qwFileSize>0)
            {
            //Determinethenumberofbytestobemappedinthisview
            DWORDdwBytesInBlock=sinf.dwAllocationGranularity;
             
            if(qwFileSize<sinf.dwAllocationGranularity)//文件小于系統分配粒度
            dwBytesInBlock=(DWORD)qwFileSize;//偏移量為文件大小
             
            PBYTEpbFile=(PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_READ,
            (DWORD)(qwFileOffset>>32),//Startingbyte
            (DWORD)(qwFileOffset&0xFFFFFFFF),//infile
            dwBytesInBlock);//#ofbytestomap
             
            PBYTEpbmyFile=(PBYTE)MapViewOfFile(hmyfilemap,FILE_MAP_WRITE,
            (DWORD)(qwmyFileOffset>>32),//Startingbyte
            (DWORD)(qwmyFileOffset&0xFFFFFFFF),//infile
            dwBytesInBlock);
             
            memcpy(pbmyFile,pbFile,dwBytesInBlock);
             
             
            //Unmaptheview;wedontwantmultipleviews
            //inouraddressspace.
            UnmapViewOfFile(pbFile);
            UnmapViewOfFile(pbmyFile);
             
            //Skiptothenextsetofbytesinthefile.
            qwmyFileOffset+=dwBytesInBlock;
            qwFileOffset+=dwBytesInBlock;
            qwFileSize-=dwBytesInBlock;
            }
             
            CloseHandle(hFileMapping);
            CloseHandle(hmyfilemap);

            參考資料:《Windows核心編程》

            Richter
            是一位讓人佩服的前輩,本文99%是引用前輩原文,原創部份甚少,請各位莫見笑(本人純屬初學者),者作深厚的技術功底與精湛的語言,讓我對內存映射文件操作有了清晰的認識,若大家有什么不清楚之處,可以聯系我,小弟愿與你們探討,

             

            posted on 2011-03-29 10:04 肥仔 閱讀(1538) 評論(0)  編輯 收藏 引用 所屬分類: Windows開發

            久久国产成人午夜AV影院| 久久男人中文字幕资源站| 久久91精品国产91久| 狠狠色丁香久久婷婷综合_中| 91麻豆精品国产91久久久久久| 91精品国产综合久久香蕉| 国产精品99久久久久久董美香| 久久高潮一级毛片免费| 亚洲AV无码久久精品狠狠爱浪潮 | 伊人久久成人成综合网222| 亚洲午夜无码久久久久| 97久久精品人人做人人爽| 欧美亚洲国产精品久久久久| 久久99久久无码毛片一区二区| 久久伊人五月丁香狠狠色| 久久久久亚洲精品中文字幕| 久久国产色av免费看| 久久人与动人物a级毛片| 国产精品美女久久久网AV| 72种姿势欧美久久久久大黄蕉| 国产—久久香蕉国产线看观看| 久久精品一区二区三区不卡| 亚洲国产精品无码久久久蜜芽 | 97久久精品人人澡人人爽| 久久Av无码精品人妻系列| 久久夜色精品国产欧美乱| 免费无码国产欧美久久18| 伊人久久大香线蕉亚洲五月天| 中文精品99久久国产| 久久99国内精品自在现线| 777米奇久久最新地址| 久久国产香蕉一区精品| 亚洲伊人久久综合中文成人网| 久久国产AVJUST麻豆| 久久夜色精品国产欧美乱| 久久99精品久久久久久动态图| 国产精品一久久香蕉国产线看 | 麻豆AV一区二区三区久久| 久久精品国产精品亚洲下载| 国产精品久久久久久久人人看| 久久se精品一区精品二区|