1.使用内存映射文件来处理文件的内容,我们先打开文件并向系统预订一块虚拟地址空间区域。接着让系统把文件的第一个字节映射到该区域的第一个字节。然后就可以访问这块虚拟内存区域,就好像它实际包含了文件一样。
2.这种方法的最大的优点在于让系统为我们处理所有与缓存有关的操作。我们不必再分配任何内存,把文件中的数据载入内存,把数据写回文件、以及释放内存块。
3.而且我们还可以通过只映射文件的一个视图(这个视图只包含文件的一小部分数据)的方式来处理大文件。
下面是代码和详细注释:
#include <iostream>
#include <windows.h>
int main()
{
SYSTEM_INFO sinf;
GetSystemInfo(&sinf);
//打开文件数据
HANDLE hFile=CreateFile("F:\\S01E01.720p.mkv",GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
//创建文件映射对象
HANDLE hFileMapping=CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);
//记录文件尺寸
DWORD dwFileSizeHight;
//GetFileSize参数为文件尺寸高字节的的指针,返回文件尺寸低字节DWORD
DWORD qwFileSizeLow=GetFileSize(hFile,&dwFileSizeHight);
__int64 qwFileSize=(((__int64)dwFileSizeHight)<<32)+(__int64)qwFileSizeLow;
CloseHandle(hFile);//不再需要文件句柄
__int64 qwFileOffset=0;//记录文件的读取位置
int qwNumOf0s=0;//记录0的个数
//设定被映射的视图大小为系统分配粒度,一般64k
DWORD dwByteInBlock=sinf.dwAllocationGranularity;
while(qwFileSize>0)
{
//如果文件剩余部分小于分配粒度
if(qwFileSize<dwByteInBlock)
dwByteInBlock=(DWORD)qwFileSize;
//映射文件视图
PBYTE pbFile=(PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_READ,
(DWORD)(qwFileOffset>>32), //
(DWORD)(qwFileOffset & 0xFFFFFFFF), //指定文件映射的开始字节
dwByteInBlock);//指定大小
//统计0的个数
for(DWORD i=0;i<dwByteInBlock;++i)
if(0==pbFile[i])
++qwNumOf0s;
UnmapViewOfFile(pbFile);
qwFileOffset+=dwByteInBlock;
qwFileSize-=dwByteInBlock;
}
CloseHandle(hFileMapping);
std::cout<<"0的个数为:"<<qwNumOf0s<<std::endl;
return 0;
}
注意:
1.这个算法会映射许多小于或等于64k(系统分配粒度)的视图。
2.MapViewOfFile要求文件的偏移量必须是分配粒度的整数倍。
3.完成算法后,需要注意清理工作。