分块内存映射处理大文件-例子

参考 :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 frames
	BOOL bLoop = TRUE;
	int	i;
	int width = 1024;
	int height = 576;
	int bitcount = 8;			//1, 4, 8, 24, 32

	//
	//Build bitmap header
	BITMAPFILEHEADER bitmapFileHeader; 
	BITMAPINFOHEADER bitmapInfoHeader; 
	BYTE			 rgbquad[4];			// RGBQUAD
	int				 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];		// 我的位图pMyBmp
	BYTE *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;										//rgbReserved
		for(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;										//rgbReserved
		for(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 system
	HANDLE 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 object
	HANDLE 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 handle
		if (hFile != INVALID_HANDLE_VALUE)
		{
			CloseHandle(hFile);
			hFile = INVALID_HANDLE_VALUE;
		}

		SetLastError(dwError);
		bLoop = FALSE;
		return FALSE;
	}

	// Retrieve allocation  granularity
	SYSTEM_INFO sinf;
	GetSystemInfo(&sinf);
	DWORD dwAllocationGranularity = sinf.dwAllocationGranularity;

	// Retrieve file size
	// Retrieve file size
	DWORD 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 Handle
		if (hMapping != NULL)
		{
			CloseHandle(hMapping);
			hMapping = NULL;
		}
		SetLastError(dwError);
		bLoop = FALSE;
		return FALSE;
	}


	BYTE  *lpBits = (BYTE *)lpData;
	BYTE  *curr1, *curr2, *lpEnd;
	curr1 = lpBits;							// seek to start
	curr2 = lpBits + 596;					// seek to first frame
	lpEnd = lpBits + dwBytesInBlock;		// seek to end

	// Read video infomation
	KMemDataStream 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;}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值