出现资源泄漏的问题。
除了前面这些必须的api函数之外,在使用内存映射文件时还要根据情况来选用其他一些辅助函数。例如,在使用内存映射文件时,为了提高速度,系统将文件的数据页面进行高速缓存,而且在处理文件映射视图时不立即更新文件的磁盘映像。为解决这个
问题可以考虑使用flushviewoffile()函数,该函数强制系统将修改过的数据部分或全部重新写入磁盘映像,从而可以确保所有的数据更新能及时保存到磁盘。
使用内存映射文件处理大文件应用示例
下面结合一个具体的实例来进一步讲述内存映射文件的使用方法。该实例从端口接收数据,并实时将其存放于磁盘,由于数据量大(几十gb),在此
选用内存映射文件进行处理。下面给出的是位于工作线程mainproc中的部分主要代码,该线程自
程序运行时启动,当端口有数据到达时将会发出事件hevent[0],waitformultipleobjects()函数等待到该事件发生后将接收到的数据保存到磁盘,如果终止接收将发出事件hevent[1],事件处理过程将负责完成资源的释放和文件的关闭等
工作。下面给出此线程处理函数的具体实现过程:
......
// 创建文件内核对象,其句柄保存于hfile
handle hfile = createfile(recv1.zip,
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);
while(bloop)
{
// 捕获事件hevent[0]和事件hevent[1]
dword ret = waitformultipleobjects(2, hevent, false, infinite);
ret -= wait_object_0;
switch (ret)
{
// 接收数据事件触发
case 0:
// 从端口接收数据并保存到内存映射文件
nreadlen=syio_read(port[1], pbfile qwfileoffset, queuelen);
qwfileoffset = nreadlen;
// 当数据写满60%时,为防数据溢出,需要在其后开辟一新的映射视图
if (qwfileoffset > t)
{
t = qwfileoffset 600 * sinf.dwallocationgranularity;
unmapviewoffile(pbfile);
pbfile = (pbyte)mapviewoffile(hfilemapping,
file_map_all_access,
(dword)(qwfileoffset>>32), (dword)(qwfileoffset&0xffffffff), dwbytesinblock);
}
break;
// 终止事件触发
case 1:
bloop = false;
// 从进程的地址空间撤消文件数据映像
unmapviewoffile(pbfile);
// 关闭文件映射对象
closehandle(hfilemapping);
break;
}
}
...
在终止事件触发处理过程中如果只简单的执行unmapviewoffile()和closehandle()函数将无法正确标识文件的实际大小,即如果开辟的内存映射文件为30gb,而接收的数据只有14gb,那么上述程序执行完后,保存的文件长度仍是30gb。也就是说,在处理完成后还要再次通过内存映射文件的形式将文件恢复到实际大小,下面是实现此要求的主要代码:
// 创建另外一个文件内核对象
hfile2 = createfile(recv.zip,
generic_write | generic_read,
file_share_read,
null,
create_always,
file_flag_sequential_scan,
null);
// 以实际数据长度创建另外一个文件映射内核对象
hfilemapping2 = createfilemapping(hfile2,
null,
page_re
adwrite,
0,
(dword)(qwfileoffset&0xffffffff),
null);
// 关闭文件内核对象
c