VC++ 中使用記憶體對應檔處理大檔案

來源:互聯網
上載者:User

先貼代碼:

#include "stdafx.h"
#include <windows.h>
#include <iostream>
using namespace std;


string GetValue(const char* lpbMapAddress, const char* sName);

int main()
{
HANDLE hFile = CreateFile(
TEXT("E:\\test.txt"),
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (hFile == INVALID_HANDLE_VALUE)
{
cout<< "建立檔案對象失敗,錯誤碼: "<<GetLastError()<<endl;
return 0;
}

//// 得到檔案尺寸
//DWORD dwFileSizeHigh;
//__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
//qwFileSize |= (((__int64)dwFileSizeHigh) << 32);

////
//DWORD sizeRead;
//_tstring strR;
//char p[MAX_PATH] = {0};
//一定要用char的數組而不能用TCHAR,因為若是UNICODE,那麼TCHAR是兩個位元組的寬字元,
//但是ReadFile只能一個位元組一個位元組的讀,這樣會把兩個單位元組字元讀到一個寬位元組裡面,
//然後把這2個字元當做一個寬位元組字元來解讀就會出錯!
//bool bRestule = ReadFile(hFile, p, qwFileSize, &sizeRead, NULL);


// 建立檔案對應物件
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hFileMap == NULL)
{
cout<<"建立檔案對應物件失敗,錯誤碼: "<<GetLastError()<<endl;
return 0;
}

// 得到系統分配粒度
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran = SysInfo.dwAllocationGranularity;

// 得到檔案尺寸
DWORD dwFileSizeHigh;
__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize |= (((__int64)dwFileSizeHigh) << 32);

// 關閉檔案對象
CloseHandle(hFile);

// 位移地址
__int64 qwFileOffset = 0;

// 塊大小
DWORD dwBlockBytes = 0;
for (int i=1; ;++i)
{
if (qwFileSize <= i * dwGran)
{
dwBlockBytes = i * dwGran;
break;
}
}

if (qwFileOffset >= 0)
{
// 映射視圖
//如果在調用MapViewOfFile()的時候,dwNumberOfBytesToMap如果大於檔案的size,那麼該call就會失敗,
//並且error code是access denied。所以MapViewOfFile的最後一個參數不能用dwBlockSize而只能用qwFileSize。
//MapViewOfFile的傳回值不能是TCHAR*,因為UNICODE時解釋成寬字元,會出錯,只能用char*
char *lpbMapAddress = (char *)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, qwFileSize);
if (lpbMapAddress == NULL)
{
cout<<"對應檔映射失敗,錯誤碼: "<<GetLastError()<<endl;
return 0;
}

string str = GetValue(lpbMapAddress, ("hkx"));
cout<<str.c_str()<<endl;

getchar();

// 撤銷檔案映像
UnmapViewOfFile(lpbMapAddress);
}

// 關閉檔案對應物件控制代碼
CloseHandle(hFileMap);

return 0;
}


string GetValue(const char* lpbMapAddress, const char* sName)
{
string str;
const char* p1 = strstr(lpbMapAddress,sName);
if (NULL != p1)
{
const char* p2 = strstr(p1, sName);
if(p2 != NULL)
{
const char* p3 = strstr(p2, "=");
if (p3 != NULL)
{
const char* p4 = p3 + 1;
str = p4;
}
}
}
return str;
}

  

引言

  檔案操作是應用程式最為基本的功能之一,Win32
API和MFC均提供有支援檔案處理的函數和類,常用的有Win32
API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile類等。一般來說,以上這些函數可以滿足大多數場合的要求,但是對於某些特殊應用領域所需要的動輒幾十GB、幾百GB、乃至幾TB的海量儲存,再以通常的檔案處理方法進行處理顯然是行不通的。目前,對於上述這種大檔案的操作一般是以記憶體對應檔的方式來加以處理的,本文下面將針對這種Windows核心編程技術展開討論。

  記憶體對應檔概述

  記憶體檔案對應也是Windows的一種記憶體管理方法,提供了一個統一的記憶體管理特徵,使應用程式可以通過記憶體指標對磁碟上的檔案進行訪問,其過程就如同對載入了檔案的記憶體的訪問。通過檔案對應這種使磁碟檔案的全部或部分內容與進程虛擬位址空間的某個地區建立映射關聯的能力,可以直接對被映射的檔案進行訪問,而不必執行檔案I/O操作也無需對檔案內容進行緩衝處理。記憶體檔案對應的這種特性是非常適合於用來管理大尺寸檔案的。

  在使用記憶體對應檔進行I/O處理時,系統對資料的傳輸按頁面來進行。至於內部的所有記憶體頁面則是由虛擬記憶體管理器來負責管理,由其來決定記憶體頁面何時被分頁到磁碟,哪些頁面應該被釋放以便為其它進程提供空閑空間,以及每個進程可以擁有超出實際分配實體記憶體之外的多少個頁面空間等等。由於虛擬記憶體管理器是以一種統一的方式來處理所有磁碟I/O的(以頁面為單位對記憶體資料進行讀寫),因此這種最佳化使其有能力以足夠快的速度來處理記憶體操作。

  使用記憶體對應檔時所進行的任何實際I/O互動都是在記憶體中進行並以標準的記憶體位址形式來訪問。磁碟的周期性分頁也是由作業系統在後台隱蔽實現的,對應用程式而言是完全透明的。記憶體對應檔的這種特性在進行大檔案的磁碟事務操作時將獲得很高的效益。

  需要說明的是,在系統的正常的分頁操作過程中,記憶體對應檔並非一成不變的,它將被定期更新。如果系統要使用的頁面目前正被某個記憶體對應檔所佔用,系統將釋放此頁面,如果頁面資料尚未儲存,系統將在釋放頁面之前自動完成頁面資料到磁碟的寫入。

  對於使用頁虛擬儲存管理的Windows作業系統,記憶體對應檔是其內部已有的記憶體管理組件的一個擴充。由可執行字碼頁面和資料頁面組成的應用程式可根據需要由作業系統來將這些頁面換進或換出記憶體。如果記憶體中的某個頁面不再需要,作業系統將撤消此頁面原擁用者對它的控制權,並釋放該頁面以供其它進程使用。只有在該頁面再次成為需求頁面時,才會從磁碟上的可執行檔重新讀入記憶體。同樣地,當一個進程初始化啟動時,記憶體的頁面將用來儲存該應用程式的靜態、動態資料,一旦對它們的操作被提交,這些頁面也將被備份至系統的分頁檔,這與可執行檔被用來備份執行字碼頁面的過程是很類似的。圖1展示了字碼頁面和資料頁面在磁碟儲存空間上的備份過程:

圖1
進程的字碼頁、資料頁在磁碟儲存空間上的備份

  顯然,如果可以採取同一種方式來處理代碼和資料頁面,無疑將會提高程式的執行效率,而記憶體對應檔的使用恰恰可以滿足此需求。

對大檔案的管理

  記憶體對應檔對象在關閉對象之前並沒有必要撤銷記憶體對應檔的所有視圖。在對象被釋放之前,所有的髒頁面將自動寫入磁碟。通過
CloseHandle()關閉記憶體對應檔對象,只是釋放該對象,如果記憶體對應檔代表的是磁碟檔案,那麼還需要調用標準檔案I/O函數來將其關閉。在處理大檔案處理時,記憶體對應檔將表示出卓越的優勢,只需要消耗極少的實體資源,對系統的影響微乎其微。下面先給出記憶體對應檔的一般編程流程框圖:

圖2
使用記憶體對應檔的一般流程

  而在某些特殊行業,經常要面對十幾GB乃至幾十GB容量的巨型檔案,而一個32位進程所擁有的虛擬位址空間只有232 =
4GB,顯然不能一次將檔案映像全部映射進來。對於這種情況只能依次將大檔案的各個部分映射到進程中的一個較小的地址空間。這需要對上面的一般流程進行適當的更改:

  1)對應檔開頭的映像。

  2)對該映像進行訪問。

  3)取消此映像

  4)映射一個從檔案中的一個更深的位移開始的新映像。

  5)重複步驟2,直到訪問完全部的檔案資料。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.