青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

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

內(nèi)存映射修改大文件

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

下載源代碼

本文介紹利用內(nèi)存映射文件修改大文件:在大文件內(nèi)存前加入一段數(shù)據(jù),若要使用內(nèi)存映射文件,必須執(zhí)行下列操作步驟:

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

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

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

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

一、我們打開關于A文件內(nèi)核對象,并創(chuàng)建一個關于B文件的內(nèi)核對象

若要創(chuàng)建或打開一個文件內(nèi)核對象,總是要調(diào)用CreateFile函數(shù):

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

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

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

含義

0

不能讀取或?qū)懭胛募膬?nèi)容,當只想獲得文件的屬性時,請設定0

GENERIC_READ

可以從文件中讀取數(shù)據(jù)

GENERIC_WRITE

可以將數(shù)據(jù)寫入文件

GENERIC_READ|GENERIC_WRITE

可以從文件中讀取數(shù)據(jù),也可以將數(shù)據(jù)寫入文件

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

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

含義

0

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

FILE_SHARE_READ

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

FILE_SHARE_WRITE

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

FILE_SHARE_READFILE_SHARE_WRITE

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

如果CreateFile函數(shù)成功地創(chuàng)建或打開指定的文件,便返回一個文件內(nèi)核對象的句柄,否則返回INVALID_HANDLE_VALUE,

注意能夠返回句柄的大多數(shù)Windows函數(shù)如果運行失敗,那么就會返回NULL,但是,CreateFile函數(shù)將返回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);

二、我們要分別創(chuàng)建兩個文件映射內(nèi)核對象

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

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

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

使用fdwProtect參數(shù)設定的部分保護屬性

保護屬性

含義

PAGE_READONLY

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

PAGE_READWRITE

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

PAGE_WRITECOPY

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

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

Windows98將忽略SEC_NOCACHE標志。

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

Windows98將忽略SEC_IMAGE標志

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

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);
}

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

在本實例中創(chuàng)建文件映射內(nèi)核對象代碼如下:

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!";              //加入的文件內(nèi)容
 
   __int64 myFilesize=qwFileSize+sinf.dwAllocationGranularity;            //合并后的文件大小
  HANDLE hmyfilemap = CreateFileMapping(hmyfile, NULL, PAGE_READWRITE,   //合并文件大小的內(nèi)存映射對象
      (DWORD)(myFilesize>>32), (DWORD)(myFilesize& 0xFFFFFFFF), NULL);

三、將文件數(shù)據(jù)映射到地址空間

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

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

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

17-6值及其含義

含義

FILE_MAP_WRITE

可以讀取和寫入文件數(shù)據(jù),CreateFileMapping函數(shù)必須通過傳遞PAGE_READWRITE標志來調(diào)用

FILE_MAP_READ

可以讀取文件數(shù)據(jù),CreateFileMapping函數(shù)可以通過傳遞下列任何一個保護屬性來調(diào)用:PAGE_READONLY,PAGE_READWRITEPAGE_WRITECOPY

FILE_MAP_ALL_ACCESS

FILE_MAP_WRITE相同

FILE_MAP_COPY

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

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

當系統(tǒng)制作原始頁面的拷貝時,系統(tǒng)將把頁面的保護屬性從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必須預先為內(nèi)存映射文件提交頁文件中的存儲器,然而,它只有在必要時才將修改后的頁面寫入頁文件,

四、從進程的地址空間撤消文件數(shù)據(jù)的映射

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

BOOLUnmapViewOfFile(PVOIDpvBaseAddress);

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

BOOLFlushViewOfFile(
PVOIDpvAddress,
SIZE_TdwNumberOfBytesToFlush);

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

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

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

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

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

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

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

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

CloseHandle(hFile);//Wenolongerneedaccesstothefileobjectshandle.
CloseHandle(hmyfile);
 
PBYTEpbmyFile=(PBYTE)MapViewOfFile(hmyfilemap,FILE_MAP_WRITE,//內(nèi)存映射視圖
0,//Startingbyte
0,//infile
sizeof(AddMsg));
memcpy(pbmyFile,AddMsg,sizeof(AddMsg));//加入內(nèi)容
UnmapViewOfFile(pbmyFile);
 
__int64qwFileOffset=0;//A文件視圖的偏移量
__int64qwmyFileOffset=sinf.dwAllocationGranularity;//合并文件視圖的遍移量
 
while(qwFileSize>0)
{
//Determinethenumberofbytestobemappedinthisview
DWORDdwBytesInBlock=sinf.dwAllocationGranularity;
 
if(qwFileSize<sinf.dwAllocationGranularity)//文件小于系統(tǒng)分配粒度
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%是引用前輩原文,原創(chuàng)部份甚少,請各位莫見笑(本人純屬初學者),者作深厚的技術(shù)功底與精湛的語言,讓我對內(nèi)存映射文件操作有了清晰的認識,若大家有什么不清楚之處,可以聯(lián)系我,小弟愿與你們探討,

 

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产精品久久人人爱蜜臀| 亚洲第一区在线| 国产精品久久久久毛片大屁完整版 | 一区二区成人精品 | 美国十次了思思久久精品导航| 99综合视频| 亚洲一级片在线观看| 性8sex亚洲区入口| 老色鬼精品视频在线观看播放| 久久精品99国产精品| 欧美91大片| 日韩一级在线观看| 久久精品色图| 欧美色图天堂网| 国产综合久久| 亚洲综合国产激情另类一区| 久久精品三级| 99视频一区| 麻豆久久精品| 国自产拍偷拍福利精品免费一| 亚洲精品美女久久久久| 久久久噜久噜久久综合| 欧美激情中文字幕一区二区 | 午夜视频一区二区| 日韩视频免费观看高清完整版| 欧美一区二区三区婷婷月色| 亚洲福利视频免费观看| 午夜精品久久久久影视 | 久久国产精品一区二区三区四区 | 国内精品久久久久久久影视蜜臀| 亚洲国产成人久久综合| 久久精品主播| 久久婷婷影院| 永久域名在线精品| 欧美mv日韩mv国产网站| 欧美一区二区三区四区视频| 国产精品久久网| 欧美亚洲一区二区三区| 午夜一级久久| 亚洲国产va精品久久久不卡综合| 麻豆成人91精品二区三区| 久久久综合网| 一区二区精品在线| 亚洲一区二区动漫| 国模叶桐国产精品一区| 欧美xx视频| 国产精品草草| 欧美第一黄网免费网站| 欧美日韩hd| 久久久在线视频| 欧美日韩少妇| 国产精品日韩在线观看| 久久精品2019中文字幕| 老色鬼精品视频在线观看播放| 亚洲片在线观看| 午夜精品久久久久久99热软件| 亚洲国产高清自拍| 亚洲一区二区三区欧美| 亚洲级视频在线观看免费1级| 亚洲精品视频一区| 在线观看日韩国产| 欧美亚洲尤物久久| 亚洲午夜日本在线观看| 女生裸体视频一区二区三区| 欧美一级一区| 国产精品久久久久久妇女6080 | 亚洲欧美经典视频| 麻豆精品传媒视频| 久久久999精品免费| 国产精品久久久久一区二区三区共| 欧美国产亚洲精品久久久8v| 国产亚洲欧美日韩一区二区| 在线亚洲成人| 久久精品盗摄| 一色屋精品视频免费看| 久久久久天天天天| 欧美插天视频在线播放| **欧美日韩vr在线| 欧美刺激性大交免费视频| 亚洲电影观看| 亚洲性感激情| 国产日韩一区二区三区| 久久青草久久| 亚洲毛片在线观看| 欧美在线播放| 亚洲精品美女免费| 亚洲伦理在线免费看| 亚洲无玛一区| 国产亚洲午夜| 欧美人与性动交cc0o| 亚洲女女做受ⅹxx高潮| 欧美国产日韩在线| 欧美一区二区精美| 亚洲欧洲另类| 国产亚洲精品aa午夜观看| 免费亚洲电影| 欧美在线欧美在线| 一本高清dvd不卡在线观看| 久久精品国产久精国产思思| 亚洲免费观看视频| 亚洲电影免费观看高清| 国产欧美日韩三级| 欧美性猛交xxxx乱大交退制版 | 可以看av的网站久久看| 亚洲色图综合久久| 亚洲国产精品第一区二区| 午夜精品久久久久久久99热浪潮 | 免费成人小视频| 欧美一级视频免费在线观看| 一个色综合av| 一本色道久久综合亚洲精品婷婷| 1000部国产精品成人观看| 黄色成人在线网址| 精品电影在线观看| 亚洲高清资源| 在线一区视频| 欧美在线观看视频一区二区三区| 亚洲欧美一区在线| 欧美专区日韩视频| 免费一级欧美在线大片| 欧美电影在线免费观看网站| 国产一区二区0| 亚洲高清不卡| 亚洲一二三级电影| 久久久久久久久久久久久久一区 | 久久久人成影片一区二区三区观看| 欧美一区三区三区高中清蜜桃| 午夜在线不卡| 欧美精品久久久久久久免费观看 | 亚洲三级观看| 午夜亚洲伦理| 欧美人与禽猛交乱配| 国内成+人亚洲| 亚洲一区二区三区精品在线| 免费成人黄色av| 亚洲免费婷婷| 欧美日韩一区综合| 亚洲观看高清完整版在线观看| 亚洲免费影院| 99精品国产一区二区青青牛奶| 久久久999国产| 韩国av一区二区三区在线观看 | 国产精品久久久久久久电影 | 国产午夜一区二区三区| 91久久精品国产91久久性色tv| 亚洲欧美另类国产| 91久久国产自产拍夜夜嗨| 久久精品免费看| 红桃视频一区| 老司机精品视频一区二区三区| 日韩亚洲欧美精品| 欧美日韩在线观看一区二区三区| 亚洲黄色免费电影| 亚洲国产1区| 欧美日韩国产首页| 欧美日韩亚洲网| 一道本一区二区| 亚洲性人人天天夜夜摸| 国产精品每日更新在线播放网址| 在线亚洲免费视频| 午夜久久资源| 影音国产精品| 亚洲精品欧美日韩| 国产精品稀缺呦系列在线| 久久久精品欧美丰满| 噜噜噜久久亚洲精品国产品小说| 在线观看日韩av| 99香蕉国产精品偷在线观看| 国产精品电影观看| 免费日韩精品中文字幕视频在线| 欧美va天堂| 久久久一区二区| 欧美日韩在线精品一区二区三区| 欧美一区二区啪啪| 欧美日韩免费在线| 牛人盗摄一区二区三区视频| 欧美日韩日日骚| 欧美成年人视频网站欧美| 国产精品国产三级国产专区53 | 欧美一区二区三区免费视频| 永久555www成人免费| 亚洲欧美日韩综合国产aⅴ| 亚洲茄子视频| 欧美不卡在线| 欧美成人激情视频| 狠狠色狠狠色综合日日五| 亚洲一区二区三区涩| 亚洲香蕉网站| 国产精品久久久久久久久久久久久久| 久久久亚洲一区| 亚洲国产精品高清久久久| 久久在线免费| 亚洲第一综合天堂另类专| 在线成人亚洲| 欧美电影在线| 亚洲特色特黄| 久久视频这里只有精品| 国外成人网址| 蜜臀va亚洲va欧美va天堂| 亚洲国产mv|