VC利用內(nèi)存映射文件處理大文件_第1頁
VC利用內(nèi)存映射文件處理大文件_第2頁
VC利用內(nèi)存映射文件處理大文件_第3頁
VC利用內(nèi)存映射文件處理大文件_第4頁
VC利用內(nèi)存映射文件處理大文件_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、VC利用內(nèi)存映射文件處理大文件(轉(zhuǎn)載)摘要:本文通過內(nèi)存映射文件的使用來對大尺寸文件進行訪問操作,同時也對內(nèi)存映射文件的相 關(guān)概念和一般編程過程作了較為詳細的介紹。關(guān)鍵詞:內(nèi)存映射文件:大文件處理:分配粒度引言文件操作是應(yīng)用程序最為基本的功能之一,Win32 API和MFC均提供冇支持文件處理的函數(shù) 和類,常用的有 Win32 API 的 CreateFile0. WriteFileO ReadFileO 和 MFC 提供的 CFile 類 等。一般來說,以上這些函數(shù)可以滿足大多數(shù)場合的要求,但是對于某些特殊應(yīng)用領(lǐng)域所需要的 動輒幾I GB、幾百GB、乃至幾TB的海屋存儲,再以通常的文件處理方

2、法進行處理顯然是行不通 的。目前,對于上述這種大文件的操作一般是以內(nèi)存映射文件的方式來加以處理的,本文下而將 針對這種Windows孩心編程技術(shù)展開討論.內(nèi)存映射文件概述內(nèi)存文件映射也是Windows的一種內(nèi)存管理方法,提供了一個統(tǒng)一的內(nèi)存管理特征,使應(yīng)用 程序可以通過內(nèi)存指針對磁盤上的文件進行訪問,英過程就如同對加載了文件的內(nèi)存的訪問。通 過文件映射這種使磁盤文件的全部或部分內(nèi)容與進程虛擬地址空間的某個區(qū)域建立映射關(guān)聯(lián)的 能力,可以直接對被映射的文件進行訪問,而不必執(zhí)行文件I/O操作也無需対文件內(nèi)容進行緩沖 處理。內(nèi)存文件映射的這種特性是非常適合于用來管理大尺寸文件的。在使用內(nèi)存映射文件進行

3、I/O處理時,系統(tǒng)對數(shù)據(jù)的傳輸按頁面來進行。至于內(nèi)部的所有內(nèi) 心頁而則是由虛擬內(nèi)心管理器來負責(zé)管理,由其來決左內(nèi)存頁而何時被分頁到磁盤,哪些頁而應(yīng) 該被禪放以便為其它進程提供空閑空間,以及每個進程可以擁有超出實際分配物理內(nèi)rrz外的多 少個頁而空間等等。由于虛擬內(nèi)存管理器是以一種統(tǒng)一的方式來處理所有磁盤I/O的(以頁而為 單位對內(nèi)存數(shù)據(jù)進行讀寫),因此這種優(yōu)化使其有能力以足夠快的速度來處理內(nèi)存操作。使用內(nèi)存映射文件時所進行的任何實際I/O交互都是在內(nèi)存中進行并以標準的內(nèi)存地址形 式來訪問。磁盤的周期性分頁也是由操作系統(tǒng)在后臺隱蔽實現(xiàn)的,對應(yīng)用程序而言是完全透明的。 內(nèi)存映射文件的這種特性在進行

4、大文件的磁盤事務(wù)操作時將獲得很髙的效益。需要說明的是,在系統(tǒng)的正常的分頁操作過程中,內(nèi)存映射文件并非一成不變的,它將被定 期更新。如果系統(tǒng)要使用的頁而目前正被某個內(nèi)存映射文件所占用,系統(tǒng)將釋放此貝而,如果頁 而數(shù)據(jù)尚未保存,系統(tǒng)將在釋放頁面之前自動完成頁而數(shù)據(jù)到磁盤的寫入。對于使用頁虛擬存儲管理的windows操作系統(tǒng),內(nèi)”映射文件是其內(nèi)部己有的內(nèi)存管理組件 的-個擴充。由可執(zhí)行代碼頁而和數(shù)據(jù)頁而組成的應(yīng)用程序可根據(jù)需要由操作系統(tǒng)來將這些頁而 換進或換出內(nèi)存.如果內(nèi)存中的某個頁而不再需要,操作系統(tǒng)將撤消此頁而原擁用者對它的控制 權(quán),并釋放該頁面以供其它進程使用。只有在該頁面再次成為需求頁面時,

5、才會從磁盤卜的可執(zhí) 行文件重新讀入內(nèi)存。同樣地,當(dāng)一個進程初始化啟動時,內(nèi)心的貝面將用來心儲該應(yīng)用程序的 靜態(tài)、動態(tài)數(shù)據(jù),一日對它們的操作被提交,這些頁面也將被備份至系統(tǒng)的頁面文件,這與可執(zhí) 行文件被用來備份執(zhí)行代碼頁面的過程是很類似的。圖1展示了代碼貝面和數(shù)據(jù)貝面在磁盤存儲 器上的備份過程:圖1進程的代碼頁、數(shù)據(jù)頁在磁盤存儲器上的備份顯然,如果可以采取同一種方式來處理代碼和數(shù)據(jù)頁面,無疑將會提高程序的執(zhí)行效率,而 內(nèi)存映射文件的使用恰恰可以滿足此需求。對大文件的仕理內(nèi)存映射文件對象在關(guān)閉對象之前并沒有必要撤銷內(nèi)存映射文件的所有視圖。在對象被釋放 之前,所有的臟頁而將自動寫入磁盤。通過Clos

6、eHandle ()關(guān)閉內(nèi)存映射文件對象,只是釋放 該對象,如果內(nèi)存映射文件代表的是磁盤文件,那么還需要調(diào)用標準文件I/O函數(shù)來將其關(guān)閉. 在處理大文件處理時,內(nèi)存映射文件將表示出卓越的優(yōu)勢,只需要消耗極少的物理資源,對系統(tǒng) 的彫響微乎其微。下面先給出內(nèi)存映射文件的一般編程流程框圖:圖2使用內(nèi)存映射文件的一般流程而在某些特殊行業(yè),經(jīng)常要而對I幾GB乃至幾I-GB容量的型文件,而一個32位進程所 擁有的虛擬地址空間只有232 = 4GB,顯然不能一次將文件映像全部映射進來。對于這種情況只 能依次將大文件的各個部分映射到進程中的一個較小的地址空間。這需要對上面的一般流程進行 適當(dāng)?shù)母模?) 映射

7、文件開頭的映像。2) 對該映像進行訪問。3) 取消此映像4) 映射一個從文件中的一個更深的位移開始的新收像。5) 重復(fù)步驟2.直到訪問完全部的文件數(shù)據(jù)。下而給出一段根據(jù)此描述而寫出的對大于4GB的文件的處理代碼:/選擇文件CFileDialog fileDlg(TRUE,* txt", NULL,"文本文件(*. txt) |*. txt 11*, this);fileDlg.m_ofn. Flags |= OFN_FILEMUSTEXIST;fileDlg. in_ofn. IpstrTitle ="通過內(nèi)存映射文件讀取數(shù)據(jù)"if (fileDlg.

8、DoModalO 二二 IDOK)/創(chuàng)建文件對象HANDLE hFile = CreateFi1e(fi1eDlg. GetPathName(), GENERIC.READ | GENERIC_WRITE,0, NULL, OPEN.EXISTING, FILE_ATTRIBUTE.NORMAL, NULL);if (hFile = INVALID_HANDLE_VALUE)TRACE C創(chuàng)建文件對象失敗,錯誤代碼:drn", GetLastError 0);return;/創(chuàng)建文件映射對彖HANDLE hFileMap = CreateFileMapping(hFile, NULL

9、, PAGE_READWRITE. 0, 0, NULL); if (hFileMap = NULL)TRACE(“創(chuàng)建文件映射對象失敗,錯誤代碼:%drn; GetLastError0);return;/得到系統(tǒng)分配粒度SYSTEM_INFO Syslnfo;GetSystemlnfo(&Syslnfo);DWORD dwGran = Syslnfo. dwAllocationGranularity;/得到文件尺寸DWORD dwFileSizeHigh;_int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);qwF訂e

10、Size |= (_int64)dwFileSizeHigh) << 32);/關(guān)閉文件對彖CloseHandle(hF訂e);/偏移地址_int64 qurf*ileOffset 二 0;/塊大小DWORD dwBlockBytes = dwGran.while (qwFileSize > 0)映射視圖if (qwFileSize < dwGran)dwBlockBytes = (DWORD)qwFileSize;LPBYTE lpbMapAddress = (LPBYTE)MapViewOfFile(hFileMap, FILE_XAP_ALL_ACCESS,(DW

11、ORD)(qwF訂eOffset » 32), (DWORD)(qwF訂eOffset & OxFFFFFFFF), dwBlockBytes);if (lpbMapAddress = NULL)TRACE("映射文件映射失敗,錯渓代碼:%drn; GetLastError0);return;/對映射的視圖進行訪問for(DWORD i = 0; i < dwBlockBytes; i+)BYTE tenp = *(lpbMapAddress + i);)/撤消文件映像UnmapVi ewOfFi1e(lpbMapAddress);/修正參數(shù)qwF訂 eOff

12、set += dwBlockBytes;qwFileSize -= dwBlockBytes;/關(guān)閉文件映射對象句柄CloseHandle(hF訂亡Nap);AfxMessageBox(z,成功完成對文件的訪問");在本例中,首先通過GetF訂eSize ()得到被處理文件長度(64位的高32位和低32位值。 然后在映射過程中設(shè)定每次映射的塊大小為1000倍的分配粒度,如果文件長度小于1000倍的 分配粒度時則將塊大小設(shè)逬為文件的實際長度。在處理過程中由映射、訪問、撤消映射構(gòu)成了 - 個循環(huán)處理。Jt中,每處理完一個文件塊后都通過關(guān)閉文件映射對象來對毎個文件塊進行整理。 Create

13、FileMapping ()、MapViewOfFile ()等函數(shù)是專門用來進行內(nèi)存文件映射處理用的。下而分別對這些關(guān)鍵函數(shù)進行說明:1) CreateFile () : CreateFil亡()函數(shù)是一個用途非常廣泛的函數(shù),在這里的用法并沒 有什么特殊的地方,但有兒點需要注意:是訪問模式參數(shù)血Des辻edAccess。該參數(shù)設(shè)過了對 文件內(nèi)核對象的訪問類型,其允許設(shè)宜的權(quán)限可以為讀權(quán)限GENERIC_READ、寫權(quán)限 GENERIC_WRITE.讀寫權(quán)限GENERIC_READ | GENERIC_WRITE和設(shè)備査詢權(quán)限0。在使用映射文件 時,只能打開那些具有可讀訪問權(quán)限的文件,即只能應(yīng)

14、用GENERIC-READ和GENERIC-READ | GENERIC_WRITE這兩種組合:另一點需要注意的是共享模式參數(shù)dwShareModeo該參數(shù)泄義J對 文件內(nèi)核對象的共享方式,其可能的設(shè)置為FILE_SHARE_READ. FILE_SHARE_WRITE和0,并可對 梵組合使用。Jt中,設(shè)宜為0時不允許共享對彖:FILE_SHARE_READ和FILE_SHARE_WRITE分別 為在要求只讀、只寫訪問的情況下才允許對象的共享。由于通過內(nèi)存映射文件可以在多個進程間共亨數(shù)據(jù),因此在進行這種應(yīng)用時應(yīng)當(dāng)考慮 加Shardlode參數(shù)設(shè)置對運行結(jié)果的彫響。2) CreateFileMa

15、pping ():該函數(shù)的作用是創(chuàng)建一個文件映射內(nèi)核對象,以告知系統(tǒng)文件 映射對象需要多大的物理存儲器。創(chuàng)建內(nèi)存映射文件對象對系統(tǒng)資源兒乎沒有什么彫響,也不會 影響進程的虛擬地址空間。除了需雯用來表示該對象的內(nèi)部資源Z外通常并不用為其分配虛擬內(nèi) 存,但是如果內(nèi)存映射文件對象是作共享內(nèi)存之用的話,就要在創(chuàng)建對象時由系統(tǒng)為內(nèi)存映射文 件的使用在系統(tǒng)頁文件中保留足夠的空間.函數(shù)第個參數(shù)hFile為標識要映射到進程的地址空間的文件的句柄。雖然由于內(nèi)存映射文件的物理存儲器是來自于磁盤上的文件,而非系統(tǒng)的頁文件,使創(chuàng)建內(nèi)存映射文件就像保留一個 地址空間區(qū)域并將物理存儲器提交給該區(qū)域一樣。第二個參數(shù)為指向文

16、件映射內(nèi)核對象的 SECURITY-ATTRIBUTES結(jié)構(gòu)的指針,由此來決定子進程能否繼冷得到返回的句柄。通常為其傳遞 NULLffI,以默認的安全屬性來禁止返回句柄的被繼承。接下來的參數(shù)用于文件被映射后設(shè)定文件映像的保護屬性。其可能的取值為 PAGE_READONLY、PAGE_READWRITE和PAGEJRITECOPY。雖然在創(chuàng)建文件映射對象時,系統(tǒng)并不 為其保留地址空間區(qū)域,也不將文件的存儲器映射到該區(qū)域。但是,在系統(tǒng)將存儲器映射到進程 的地址空間中去時,系統(tǒng)必須確切知道應(yīng)賦予物理存儲器貝面的保護屬性。在設(shè)豐保護屬性時, 必須與用CreateFile ()函數(shù)打開文件時所指泄的訪問

17、標識相匹配,否則將導(dǎo)致 CreateFileMapping ()的執(zhí)行失敗。因此這里設(shè)程PAGE_READWRITE屬性。除了上述三個頁而 保護屬性外,還有4個區(qū)(Section)保護屬性也可以一起組合使用:區(qū)保護屬性說明SEC.COIIIT為區(qū)中的所有頁而在內(nèi)存中或磁盤頁而文件中分配物理存儲器SECJMAGE告知系統(tǒng),映射的文件是一個可移植的EXE文件映像SEC_NOCACHE告知系統(tǒng),未將文件的任何內(nèi)存映射文件放入高速緩存,多供硬件設(shè)備驅(qū)動 程序開發(fā)人員使用SEC.RESERVE對一個區(qū)的所有頁面進行保留而不分配物理存儲器后而的兩個參數(shù)指定耍創(chuàng)建的文件映射對象的瑕大字節(jié)數(shù)的髙32位值和低3

18、2位值,實際也就 設(shè)定了文件的最大字節(jié)數(shù)(最大可以處理16EB的文件)。這兩個參數(shù)可以滿足確保文件映射對 象能夠得到足夠的物理存儲器這一基本條件。在參數(shù)設(shè)置的大小小于文件實際大小時,系統(tǒng)將從 文件映射指宦的字節(jié)數(shù)。這里將其設(shè)置為0,將使所創(chuàng)建的文件映射對象將為文件的當(dāng)前大小, 以上兩種情況均無法改變文件的大小。如果設(shè)置的參數(shù)大于文件的實際大小,系統(tǒng)將會在 CreateFileMapping ()函數(shù)返回前擴展該文件。需要指出的是,文件映射對象的大小是靜態(tài)的, 一日創(chuàng)建完畢后將無法更改。如果設(shè)程的文件映射對象尺寸偏小將導(dǎo)致無法對文件進行全面的訪 問。在本節(jié)開始也曾提到過,創(chuàng)建文件映射對象是不需要

19、花費什么系統(tǒng)資源的,因此遵循寧多 勿缺"的原則,一般應(yīng)將文件映射對象的大小設(shè)置為文件大小的相同值。幣數(shù)最后的參數(shù)將可以 為映射對象命名。如果想打開一個己存住的文件映射對象,該對象必須耍命名。對該名字字符串 的要求僅限于未被其它對象使用過的名字即可。3) MapViewOfFile ():當(dāng)創(chuàng)建了 -個內(nèi)存映射文件對象并得到其右效句柄丿二該句柄即可用來 在進程的虛擬地址空間中映射文件的一個映像.在內(nèi)存映射文件對象己經(jīng)存在的情況下,映像可 被任意映射或取消映射。在文件映像被映射時,仍然必須由系統(tǒng)來為文件的數(shù)據(jù)保留一個地址空 間【X域,并將乂件的數(shù)據(jù)作為映射到該區(qū)域的物理存儲器進行提交 在

20、進程的地址空間中,個 足夠大的連續(xù)地址空間(通常足以覆蓋整個文件映像)將被指定給此文件映像。盡管如此,內(nèi)存 的物理頁而還是根據(jù)在實際使用中的需求而進行分配的。克正分配-個對應(yīng)于內(nèi)存映射文件映像 頁血的物理內(nèi)療頁血是在發(fā)生該頁的缺貝中斷時進行的,這將在第一次讀與內(nèi)療頁血中的任一地 址時自動完成。MapViewOfFile ()即負責(zé)映射內(nèi)存映射文件的一個映像,函數(shù)的第一個參數(shù)為CreateF訂eJIapping()所返回的內(nèi)存映射文件對象句柄,第二個參數(shù) 指泄了對文件映像的訪問類型,可能取值有FILE_MAP_WRITE. FILE_MAP_READ.FILE_MAP_ALL_ACCESS和FI

21、LE_MAP_COPY等幾種JI體的設(shè)豊要根據(jù)文件映射對象允許的保護模 式而定。根據(jù)前面代碼的設(shè)置,這里應(yīng)該使用FILE_IAP_ALL_ACCESS參數(shù)。這種機制為對象的 創(chuàng)建者提供了對映射此對象的方式進行控制的能力。接卜來的2個參數(shù)分別指定了內(nèi)存映射文件 的64位偏移地址的低32位和高32位地址,該地址是從內(nèi)存映射文件頭位置到映像開始位置的 距離。最后的參數(shù)指定了視圖的大小,如果設(shè)程為0,前而的偏移地址將被忽略,系統(tǒng)將會把整 個文件映射為一個映像。MapViewOfFile ()如果成功執(zhí)行,將返回一個指向文件映像在進程的 地址空間中的起始地址的指針。如果失敗,則返回NULLe在進程中,可

22、以為同一個文件映射對 象創(chuàng)建多個文件映像,這些映像可以在系統(tǒng)中共存和重疊,也可以與對應(yīng)的文件映射對象大小不 相一致,但不能大于文件映射對象的大小.4) UnmViewOfFile ():當(dāng)不再需要保留映射到進程地址空間區(qū)域中的文件映像數(shù)據(jù)時, 可通過調(diào)用UnmapViewOfFile ()函數(shù)將其釋放.該函數(shù)結(jié)構(gòu)非常簡單,只需要提供映像在進程 中的起始地址(區(qū)域的基地址)作為參數(shù)即可。該函數(shù)的輸入?yún)?shù)為調(diào)用MapViewOfFile ()時 所返回的指向文件映像在進程的地址空間中的起始地址的指針。在調(diào)用MapViewOfFile ()后, 必須確保在進程退出之前能夠執(zhí)行UnmapViewOfFile ()函數(shù),否則在進程終止之后先前保留的 區(qū)域?qū)⒌貌坏结尫?,即使再次啟動進程重復(fù)調(diào)用MapViewOfFil

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論