引言
通常情况下,我们使用文件读写函数对文件进行处理,比如Win32 API 的CreateFile()、WriteFile()、ReadFile()等。
但是对于某些特殊应用领域,需要几十GB、几百GB的海量存储,常规处理方法显然行不通了,目前对于这种大文件的操作一般是以内存映射的方式来加以处理的。
CreateFile():用来创建一个读文件的句柄;
CreateFileMapping():创建一个文件映射对象;
MapViewOfFile(): 获得文件第一个字节的指针,通过该指针可以得到文件中的全部内容;
最后,CloseHandle()关闭文件对象和文件映射对象;
UnmapViewOfFile():用来释放文件数据映射。
实践
在书上看了几个例子,虽然对小型文件访问成功,但是对于大型文件就不行了——出错,可见作者也没有真正将“访问大型文件”的优势,在代码中体现出来——如果仅仅是读取小文件、几个字节,我何必使用文件映射这么麻烦的手段呢?
不过好在天无绝人之路,一边自己尝试、一边google相关的资料,终于解决了大型文件访问的问题;我映射了一个2GB的ghost文件,成功......
在此感谢:http://tech.ccidnet.com/art/1081/20060410/501669_1.html (搜索:MapViewOfFile、大型文件映射、映射文件、代码,找到这篇文章,其中部分文字描述与书上雷同)
SYSTEM_INFO sinf;
GetSystemInfo(&sinf);
DWORD dwAllocationGranularity = sinf.dwAllocationGranularity;
// 创建文件内核对象,其句柄保存于hFile
HANDLE hFile = CreateFile("d://sys.GHO",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
// 创建文件映射内核对象,句柄保存于hFileMapping
HANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,
0, 0x4000000, NULL);
// 释放文件内核对象
CloseHandle(hFile);
// 设定大小、偏移量等参数
__int64 qwFileSize = 0x4000000;
__int64 qwFileOffset = 0;
__int64 T = 600 * sinf.dwAllocationGranularity;
DWORD dwBytesInBlock = 1000 * sinf.dwAllocationGranularity;
// 将文件数据映射到进程的地址空间
PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
应用举例
这里有一个简单例子:http://www.cnblogs.com/stuarts/archive/2010/07/08/1773844.html
说它简单,因为:1. 数据样本简单(整个文件中全部是int数);2. 排序算法简单(冒泡)。
程序功能:将外部文件映射为一块内存,使用指针排序。
该例子说明:1 使用内存映射文件,可以避免“外排序”算法复杂度较高的尴尬;2 实现代码简单、结构清晰。
替代方案
C#里面使用Read、ReadLine方法、Stream类库,可以很方便地读取、写入大于4G的文件(未编程验证)。