上一篇介绍了一种常见的文件处理方法(可优化为:分次读取文件,但要满足根据行号能快速索引该行内容时会遇到麻烦),所以此片我将介绍另一种更高效,实用,并对本进程的内存空间地址消耗小的方法!
一. 预备知识
1). Windows编程处理文件的相关接口:
A)CreateFile();
B)ReadFile();
c)WriteFile();
d)CloseHandle();
2). 文件映射相关接口:
A) CreateFileMapping()
B)MapFIleOfView()
C)OpenFileMapping()
D)CloseHandle()
3)注:
由于以上接口MSDN以及网上的牛人们已经给了详细的介绍了,这里我只累叙 一下MapViewOfFile()第四个参数 DWORD dwFileOffsetLow;
此偏移量必须64k对齐,可能是由于便于内存管理得快速访问,才做此限定,如下代码:
LARGE_INTEGER liOffset = {};liOffset.QuadPart = lpLineInfo->liHeadCharOffset.QuadPart & (~MemmoryHex_64k);DWORD DValue = DWORD(lpLineInfo->liHeadCharOffset.QuadPart - liOffset.QuadPart);char *lpHeadSrc = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, liOffset.HighPart, liOffset.LowPart, (DValue + lpLineInfo->LineCount));
二.思想
1) 在处理文件过程中,我们一般采用的方法是分块(如每次512k)读取文件数据进行处理,这样做的目的如下
A)申请小块内存速度快
B)可以不用New动态创建存数据的Buffer,而是直接可以用栈存储次Buffer,降低内存泄漏的风险
C)若一次申请一块较大的地址空间(>512M),那你还让其他线程工作吗?一个进程中的多个线程是共用同一块地址空间的!
对于B:有朋友会说,那可以将进程中允许访问的栈空间调大(1G),但这样是有风险的,比如你在编写递归代码时出错,可能导致死循环,由于堆设得过大,导致要许久才会导致栈溢出,增加我们调式bug得难度!而当栈的空间地址范围较小时,函数调用栈很快就会溢出,Buf易复现,就便于修改了!
2)当文件大小在允许访问内(我的机器<24G),将文件内容映射到内存上,对文件的访问速率相当于内存的读取率;
A)注:我的公司开发机:Win7 64位,16G运行内存,15G虚拟内存)
B)由于映射的内存块可以被本机的其他进程访问,所以我们通常也称之为共享内存!
3)每次映射小块文件数据到次进程的地址空间上,进行处理(与上篇中处理方式一样)
DWORD RelMapMemorySize = DWORD((liTotalFileSize.QuadPart - liHandleFileSize.QuadPart + DValue > EachMapMemorySzie) ? EachMapMemorySzie : (liTotalFileSize.QuadPart - liHandleFileSize.QuadPart + DValue));lpHeadSrc = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, liOffset.HighPart, liOffset.LowPart, RelMapMemorySize);
4)根据行号索引该行内容,相当于随机访问数组的速率
相交与上篇,此篇存储每一行信息的数据结构有所改变,如下
typedef struct LINE_INFO{LARGE_INTEGER liHeadCharOffset;INT32 LineCount;}LINE_INFO;
A)我们根据liHeadCharOffset算出映射时候的偏移量!
B)注意:我们必须保证此低字节的偏移量必须64K对其,所以这里必须先对liHeadCharOffset进行处理!
a)映射偏移量首先对此值取商
LARGE_INTEGER liOffset = {};liOffset.QuadPart = lpLineInfo->liHeadCharOffset.QuadPart & (~MemmoryHex_64k);DWORD DValue = DWORD(lpLineInfo->liHeadCharOffset.QuadPart - liOffset.QuadPart);
b)处理时再加上我们做商时舍弃的差值
char *lpHeadSrc = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, liOffset.HighPart, liOffset.LowPart, (DValue + lpLineInfo->LineCount));if (NULL == lpHeadSrc){m_lpHLog->TraceLog("Error(%s.%d): MapViewOfFile Failed!\r\n", __FUNCTION__, __LINE__);return FALSE;}char *lpHead = lpHeadSrc + DValue;