參考 :http://user.qzone.qq.com/382164370/infocenter#!app=2&via=QZ.HashRefresh&pos=1363445766
內(nèi)存映射文件可以用于3個不同的目的
? 系統(tǒng)使用內(nèi)存映射文件,以便加載和執(zhí)行. exe和DLL文件。這可以大大節(jié)省頁文件空間和應用程序啟動運行所需的時間。
? 可以使用內(nèi)存映射文件來訪問磁盤上的數(shù)據(jù)文件。這使你可以不必對文件執(zhí)行I/O操作,并且可以不必對文件內(nèi)容進行緩存。
? 可以使用內(nèi)存映射文件,使同一臺計算機上運行的多個進程能夠相互之間共享數(shù)據(jù)。Windows確實提供了其他一些方法,以便在進程之間進行數(shù)據(jù)通信,但是這些方法都是使用內(nèi)存映射文件來實現(xiàn)的,這使得內(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)?關(guān)閉文件映射內(nèi)核對象。
3)?關(guān)閉文件內(nèi)核對象。
? ? ? 文件操作是應用程序最為基本的功能之一,Win32 API和MFC均提供有支持文件處理的函數(shù)和類,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile類等。一般來說,以上這些函數(shù)可以滿足大多數(shù)場合的要求,但是對于某些特殊應用領(lǐng)域所需要的動輒幾十GB、幾百GB、乃至幾TB的海量存儲,再以通常的文件處理方法進行處理顯然是行不通的。所以可以使用內(nèi)存文件映射來處理數(shù)據(jù),網(wǎng)上也有鋪天蓋地的文章,但是映射大文件的時候又往往會出錯,需要進行文件分塊內(nèi)存映射,這里就是這樣的一個例子,教你如何把文件分塊映射到內(nèi)存。
//
// 該函數(shù)用于讀取從CCD攝像頭采集來的RAW視頻數(shù)據(jù)當中的某一幀圖像,
// RAW視頻前596字節(jié)為頭部信息,可以從其中讀出視頻總的幀數(shù),
// 幀格式為1024*576*8
/*
參數(shù):pszPath:文件名dwFrame: 要讀取第幾幀,默認讀取第2幀
*/
BOOL MyFreeImage::LoadXRFrames(TCHAR *pszPath, DWORD dwFrame/* = 2*/ )
{// get the frames of X-Ray framesBOOL bLoop = TRUE;int i;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的倍數(shù) DWORD的倍數(shù) 這里是 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;} //構(gòu)造Bitmap文件頭BITMAPFILEHEADER bitmapFileHeader.bfType = 0x4d42; // 很重要的標志位 BM 標識bitmapFileHeader.bfSize = (DWORD)(bitmapFileHeader.bfOffBits + height * widthbytes); //bmp文件長度 bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; //構(gòu)造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; //創(chuàng)建BMP內(nèi)存映像,寫入位圖頭部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);//構(gòu)造調(diào)色板 , 當像素大于8位時,就沒有調(diào)色板了。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); } } //// 文件映射,從文件中查找圖像的數(shù)據(jù)//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; // 計算一幀圖像的數(shù)據(jù)量,不包括頭部信息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; //內(nèi)存緩沖剩余的字節(jié)if ( dwTmp >= dwFrameSize ) {if(dwCurrentFrame == dwFrame){memcpy(curr, curr2, dwFrameSize);bLoop = FALSE;}curr2 += dwFrameSize;}else //內(nèi)存中不夠一幀數(shù)據(jù){DWORD dwTmp2 = dwFrameSize - dwTmp; // 一副完整的幀還需要dwTmp2字節(jié)if (dwCurrentFrame == dwFrame){memcpy(curr, curr2, dwTmp);curr += dwTmp;}
?
//1、首先計算文件的偏移位置 qwFileOffset += dwBytesInBlock;//2、 檢查還可以映射多少字節(jié)的東東到內(nèi)存里面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) // 一定要檢查,不然可能內(nèi)存映射失敗{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;}}//將內(nèi)存流 pMyBmp 轉(zhuǎn)為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;}
總結(jié)
以上是生活随笔為你收集整理的分块内存映射处理大文件-例子的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。