參考 :http://user.qzone.qq.com/382164370/infocenter#!app=2&via=QZ.HashRefresh&pos=1363445766
記憶體對應檔可以用於3個不同的目的
• 系統使用記憶體對應檔,以便載入和執行. exe和DLL檔案。這可以大大節省頁檔案空間和應用程式啟動運行所需的時間。
• 可以使用記憶體對應檔來訪問磁碟上的資料檔案。這使你可以不必對檔案執行I/O操作,並且可以不必對檔案內容進行緩衝。
• 可以使用記憶體對應檔,使同一台電腦上啟動並執行多個進程能夠相互之間共用資料。Windows確實提供了其他一些方法,以便在進程之間進行資料通訊,但是這些方法都是使用記憶體對應檔來實現的,這使得記憶體對應檔成為單個電腦上的多個進程互相進行通訊的最有效方法。
使用記憶體映射資料檔案
若要使用記憶體對應檔,必須執行下列操作步驟:
1) 建立或開啟一個檔案核心對象,該對象用於標識磁碟上你想用作記憶體對應檔的檔案。
2) 建立一個檔案對應核心對象,告訴系統該檔案的大小和你打算如何訪問該檔案。
3) 讓系統將檔案對應物件的全部或一部分映射到你的進程地址空間中。
當完成對記憶體對應檔的使用時,必須執行下面這些步驟將它清除:
1) 告訴系統從你的進程的地址空間中恢復檔案映射核心對象的映像。
2) 關閉檔案對應核心對象。
3) 關閉檔案核心對象。
檔案操作是應用程式最為基本的功能之一,Win32 API和MFC均提供有支援檔案處理的函數和類,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile類等。一般來說,以上這些函數可以滿足大多數場合的要求,但是對於某些特殊應用領域所需要的動輒幾十GB、幾百GB、乃至幾TB的海量儲存,再以通常的檔案處理方法進行處理顯然是行不通的。所以可以使用記憶體檔案對應來處理資料,網上也有鋪天蓋地的文章,但是映射大檔案的時候又往往會出錯,需要進行檔案分塊記憶體映射,這裡就是這樣的一個例子,教你如何把檔案分區塊對應到記憶體。
//////////////////////////////////////////////////////////////////////////// 該函數用於讀取從CCD網路攝影機採集來的RAW視頻資料當中的某一幀映像,// RAW視頻前596位元組為頭部資訊,可以從其中讀出視頻總的幀數,// 框架格式為1024*576*8/* 參數:pszPath:檔案名稱dwFrame: 要讀取第幾幀,預設讀取第2幀*/BOOL MyFreeImage::LoadXRFrames(TCHAR *pszPath, DWORD dwFrame/* = 2*/ ){// get the frames of X-Ray framesBOOL bLoop = TRUE;inti;int width = 1024;int height = 576;int bitcount = 8;//1, 4, 8, 24, 32////////////////////////////////////////////////////////////////////////////Build bitmap headerBITMAPFILEHEADER bitmapFileHeader; BITMAPINFOHEADER bitmapInfoHeader; BYTE rgbquad[4];// RGBQUADint index = 0;DWORD widthbytes = ((bitcount*width + 31)/32)*4;//每行都是4的倍數 DWORD的倍數 這裡是 576-TRACE1("widthbytes=%d\n", widthbytes);switch(bitcount) { case 1: index = 2; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2*4); break; case 4: index = 16; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 16*4); break; case 8: index = 256; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)); break; case 24: case 32: index = 0; bitmapFileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)); break; default:break;} //構造Bitmap檔案頭BITMAPFILEHEADER bitmapFileHeader.bfType = 0x4d42; // 很重要的標誌位 BM 標識bitmapFileHeader.bfSize = (DWORD)(bitmapFileHeader.bfOffBits + height * widthbytes);//bmp檔案長度 bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; //構造Bitmap檔案資訊頭BITMAPINFOHEADER bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biWidth = width; bitmapInfoHeader.biHeight = height; bitmapInfoHeader.biPlanes = 1; bitmapInfoHeader.biBitCount = bitcount;bitmapInfoHeader.biCompression = BI_RGB; // 未壓縮bitmapInfoHeader.biSizeImage = height * widthbytes; bitmapInfoHeader.biXPelsPerMeter = 3780; bitmapInfoHeader.biYPelsPerMeter = 3780; bitmapInfoHeader.biClrUsed = 0; bitmapInfoHeader.biClrImportant = 0; //建立BMP記憶體映像,寫入位元影像頭部BYTE *pMyBmp = new BYTE[bitmapFileHeader.bfSize];// 我的位元影像pMyBmpBYTE *curr = pMyBmp;// curr指標指示pMyBmp的位置memset(curr, 0, bitmapFileHeader.bfSize); //寫入頭資訊 memcpy(curr, &bitmapFileHeader,sizeof(BITMAPFILEHEADER));curr = pMyBmp + sizeof(BITMAPFILEHEADER); memcpy(curr, &bitmapInfoHeader,sizeof(BITMAPINFOHEADER)); curr += sizeof(BITMAPINFOHEADER);//構造調色盤 , 當像素大於8位時,就沒有調色盤了。if(bitcount == 8) {rgbquad[3] = 0;//rgbReservedfor(i = 0; i < index; i++) { rgbquad[0] = rgbquad[1] = rgbquad[2] = i; memcpy(curr, rgbquad, sizeof(RGBQUAD)); curr += sizeof(RGBQUAD); } }else if(bitcount == 1) { rgbquad[3] = 0;//rgbReservedfor(i = 0; i < index; i++) { rgbquad[0] = rgbquad[1] = rgbquad[2] = (256 - i)%256; memcpy(curr, rgbquad, sizeof(RGBQUAD)); curr += sizeof(RGBQUAD); } } //////////////////////////////////////////////////////////////////////////// 檔案對應,從檔案中尋找映像的資料//Open the real file on the file systemHANDLE hFile = CreateFile(pszPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE){DWORD dwError = GetLastError();ATLTRACE(_T("MapFile, Failed in call to CreateFile, Error:%d\n"), dwError);SetLastError(dwError);bLoop = FALSE;return FALSE;}//Create the file mapping objectHANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);if (hMapping == NULL){DWORD dwError = GetLastError();ATLTRACE(_T("MapFile, Failed in call to CreateFileMapping, Error:%d\n"), dwError);// Close handleif (hFile != INVALID_HANDLE_VALUE){CloseHandle(hFile);hFile = INVALID_HANDLE_VALUE;}SetLastError(dwError);bLoop = FALSE;return FALSE;}// Retrieve allocation granularitySYSTEM_INFO sinf;GetSystemInfo(&sinf);DWORD dwAllocationGranularity = sinf.dwAllocationGranularity;// Retrieve file size// Retrieve file sizeDWORD dwFileSizeHigh;__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);qwFileSize |= (((__int64)dwFileSizeHigh) << 32);CloseHandle(hFile);// Read Image__int64 qwFileOffset = 0;// 位移地址DWORD dwBytesInBlock = 0,// 映射的塊大小dwStandardBlock = 100* dwAllocationGranularity ;// 標準塊大小DWORD dwFrameSize = height*width; // 計算一幀映像的資料量,不包括頭部資訊DWORD dwCurrentFrame = 1;dwBytesInBlock = dwStandardBlock;if (qwFileSize < dwStandardBlock)dwBytesInBlock = (DWORD)qwFileSize;//Map the view LPVOID lpData = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS, static_cast<DWORD>((qwFileOffset & 0xFFFFFFFF00000000) >> 32), static_cast<DWORD>(qwFileOffset & 0xFFFFFFFF), dwBytesInBlock);if (lpData == NULL){DWORD dwError = GetLastError();ATLTRACE(_T("MapFile, Failed in call to MapViewOfFile, Error:%d\n"), dwError);// Close Handleif (hMapping != NULL){CloseHandle(hMapping);hMapping = NULL;}SetLastError(dwError);bLoop = FALSE;return FALSE;}BYTE *lpBits = (BYTE *)lpData;BYTE *curr1, *curr2, *lpEnd;curr1 = lpBits;// seek to startcurr2 = lpBits + 596;// seek to first framelpEnd = lpBits + dwBytesInBlock;// seek to end// Read video infomationKMemDataStream streamData( curr1, dwBytesInBlock);ReadXRHeader(streamData);while(bLoop){DWORD dwTmp = lpEnd - curr2;//記憶體緩衝剩餘的位元組if ( dwTmp >= dwFrameSize ){if(dwCurrentFrame == dwFrame){memcpy(curr, curr2, dwFrameSize);bLoop = FALSE;}curr2 += dwFrameSize;}else//記憶體中不夠一幀資料{DWORD dwTmp2 = dwFrameSize - dwTmp;// 一副完整的幀還需要dwTmp2位元組if (dwCurrentFrame == dwFrame){memcpy(curr, curr2, dwTmp);curr += dwTmp;}
//1、首先計算檔案的位移位置
qwFileOffset += dwBytesInBlock;
//2、 檢查還可以映射多少位元組的東東到記憶體裡面if ( qwFileSize - qwFileOffset < dwStandardBlock)dwBytesInBlock = (DWORD)(qwFileSize - qwFileOffset);//3、重新對應檔案UnmapViewOfFile(lpData);lpData = MapViewOfFile(hMapping, FILE_MAP_ALL_ACCESS,
static_cast<DWORD>((qwFileOffset & 0xFFFFFFFF00000000) >> 32), static_cast<DWORD>(qwFileOffset & 0xFFFFFFFF), dwBytesInBlock);if (lpData == NULL) // 一定要檢查,不然可能記憶體映射失敗{DWORD dwError = GetLastError();ATLTRACE(_T("MapFile, Failed in call to MapViewOfFile, Error:%d\n"),
dwError);SetLastError(dwError);bLoop = FALSE;break;}curr2 = lpBits = (BYTE *)lpData;lpEnd = lpBits + dwBytesInBlock; // seek to endif (dwCurrentFrame == dwFrame){memcpy(curr, curr2, dwTmp2);bLoop = FALSE;}curr2 += dwTmp2;}dwCurrentFrame++;if (dwCurrentFrame
> ((LPKINFO)m_VideoInfoHeader)->frames ) // 到達檔案末尾{bLoop = FALSE;}}//將記憶體流 pMyBmp 轉為bitmapKMemDataStream stream(pMyBmp, bitmapFileHeader.bfSize, true);if(!LoadFromMemory(FIF_BMP, stream))return FALSE;//if (lpData != NULL){//FlushViewOfFile(lpData, 0);UnmapViewOfFile(lpData);lpData
= NULL;}//remove the file mappingif (hMapping != NULL){CloseHandle(hMapping);hMapping = NULL;}return TRUE;}