内存映射文件

      内存映射文件,是由一个文件到一块内存的映射。Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
// FileMap.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

#define BUFFSIZE		1024          //内存大小
#define FILE_MAP_START	0x28804		  //文件映射的起始地址

LPTSTR  lpcTheFile	=	TEXT("test.dat");
int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE	hMapFile;				//	文件内存映射区域的句柄
	HANDLE	hFile;					//	文件句柄
	DWORD	dByteWritten;			//	写入的字节数
	DWORD	dwFileSize;				//	文件大小
	DWORD	dwFileMapStart;			//	文件映射视图的起始地址
	DWORD	dwMapViewSize;			//	视图大小
	DWORD	dwFileMapSize;			//	文件映射大小
	DWORD	dwSysGran;				//	系统内存分配的粒度
	SYSTEM_INFO SysInfo;			//	系统信息
	LPVOID	lpMapAddress;			//	内存映射区域的起始地址
	PCHAR	pData;					//	数据
	INT		i;
	INT		iData;
	INT		iViewData;
	BYTE	cMapBuffer[32];			//	存储从mapping中计出的数据

	hFile = CreateFile(lpcTheFile,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if(hFile == INVALID_HANDLE_VALUE)
	{
		printf("CreateFile error\n",GetLastError);
		return 1;
	}
	
	for( i = 0; i < 65535; i++)
	{
		WriteFile(hFile, &i, sizeof(i),&dByteWritten, NULL);
	}
	
	dwFileSize = GetFileSize(hFile,NULL);
	printf("文件大小: %d\n", dwFileSize);

	//获取系统信息,内存分配粒度
	//获取分配粒度,进行下面计算
	//目的是为了映射的数据与系统内存分配粒度对齐,提高内存的访问效率

	GetSystemInfo(&SysInfo);
	dwSysGran = SysInfo.dwAllocationGranularity;      // 65536 =  64kb

	//计算mapping的起始位置  如果 FILE_MAP_START 为奇数 改成 偶数地址
	//分配的粒度是内存最小分配大小。
	//比如你在0x10的地方申请分配4097个字节的内存,
	//那么实际分配的大小是4097/4k+4K=8K的大小。
	dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;      
	//计算mapping_view的大小
	dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;
	//计算mapping的大小
	dwFileMapSize = FILE_MAP_START + BUFFSIZE;
	//计算需要读取的数据的偏移
	iViewData= FILE_MAP_START - dwFileMapStart;
	//创建File mapping
	hMapFile = CreateFileMapping( hFile,       //需要映射的文件句柄
		NULL,								   //安全选项:默认
		PAGE_READWRITE,						   //可读,可写
		0,									   //mapping对象的大小,高位
		dwFileMapSize,						   //mapping对象的大小,低位
		NULL);								   //mapping对象的名字

	if( hMapFile == NULL)
	{
		printf("CreateFileMapping error: %d\n",GetLastError());
		return 1;
	}

	lpMapAddress = MapViewOfFile( hMapFile, 
		FILE_MAP_ALL_ACCESS,
		0,
		dwFileMapStart,
		dwMapViewSize);
	
	if (lpMapAddress == NULL)
	{
		printf("MapViewOfFile error:%d\n",GetLastError());
		return 1;
	}
	printf("文件map view相当于文件的起始位置: 0x%x\n",dwFileMapStart);
	printf("文件map view的大小: x%x\n",dwMapViewSize);
	printf("文件mapping对象的大小: x%x\n",dwFileMapSize);
	printf("从相对于map view 0x%x 字节的位置读取数据,", iViewData);
	//将指向数据的指针偏移,到达我们关心的地方
	pData = (PCHAR)lpMapAddress + iViewData;
	//读取数据,赋值给变量
	iData = *(PINT)pData;
	printf("为: x%.8x\n",iData);
	//从mapping中复制数据,32个字节,并打印
	CopyMemory(cMapBuffer,lpMapAddress,32);
	printf("lpMapAddress起始字节是:");
	for( i = 0; i < 32; i++)
	{
		printf("0x%.2x ",cMapBuffer[i]);
	}
	//将mapping的前32个字节用0xff填充
	FillMemory(lpMapAddress,32,(BYTE)0xff);
	//将映射的数据写回到硬盘上
	FlushViewOfFile(lpMapAddress,dwMapViewSize);
	printf("\n已经将lpMapAddress开始的字节使用0xff填充");
	//关闭mapping对象
	if(!CloseHandle(hMapFile))
	{
		printf("\nclosing the mapping object error %d!",GetLastError());
	}
	//关闭文件
	if(!CloseHandle(hFile))
	{
		printf("\nError %ld occurred closing the file!",GetLastError());
	}
	
	printf("\n");
	return 0;
}

/*
现代计算机读取内存的时候,一般只能在偶数边界上开始读,
什么意思呢,我们打个比方,在32位的机子上,一个int变量
变量占用4字节,假如这个变量的真实物理内存地址是0x400005,
那计算机在取数的时候会先从0x400004取4个字节,
再从0x400008取4个字节,然后这个变量的值就是前4个字节的
后三位和后4个字节的第一位,也就是说如果一个变量的地址从
奇数开始,就可能要多读一次内存,而如果落在从偶数开始,特
别是计算机位数/8的倍数开始,效率就高了
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值