由于某种需要,很多时候可能需要对文件进行随机偏移读取和修改。一般情况下,可以先fseek到文件中制定的位置,再将文件块读入内存-修改-写回。 对于大文件(GB量级),或者频繁的随机文件读写,这样的方式会非常耗费时间。
这类操作一般是以内存映射文件(即将文件映射到进程的某一块空间)的方式来加以处理的。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行 I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,所以效率大大提高。
下面试总结的内存文件映射使用方式:
//开始
//获得文件句柄
HANDLE hFile=CreateFile(
"data.dat", //文件名
GENERIC_READ|GENERIC_WRITE, //对文件进行读写操作
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING, //打开已存在文件
FILE_ATTRIBUTE_NORMAL,
0);
//返回值size_high,size_low分别表示文件大小的高32位/低32位
DWORD size_low,size_high;
size_low= GetFileSize(hFile,&size_high);
//创建文件的内存映射文件。
HANDLE hMapFile=CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE, //对映射文件进行读写
size_high,
size_low, //这两个参数共64位,所以支持的{zd0}文件长度为16EB
NULL);
if(hMapFile==INVALID_HANDLE_VALUE)
{
AfxMessageBox("Can't create file mapping.Error%d:\n", GetLastError());
CloseHandle(hFile);
return;
}
//把文件数据映射到进程的地址空间
void* pvFile=MapViewOfFile(
hMapFile,
FILE_MAP_READ|FILE_MAP_WRITE,
0,
0,
0);
unsigned char *p=(unsigned char*)pvFile;
//至此,就获得了外部文件data.dat在内存地址空间的映射,
//下面就可以用指针p"折磨"这个文件了
CString s;
p[size_low-1]=0x1f;
p[size_low-2]=0x2f; //修改该文件的{zh1}两个字节(文件大小<4GB高32位为0)
s.Format("%#x,%#x,%#x",p[size_low-3],p[size_low-2],p[size_low-1]);
//读文件的{zh1}3个字节
AfxMessageBox(s);
//结束
UnmapViewOfFile(pvFile); //撤销映射
CloseHandle(hFile); //关闭文件