qt 内存映射文件如何映射大文件,超过4G就报磁盘空间不足

请教高手:如何在linux下用mmap映射超大文件,并读取其内容?-CSDN论坛
应用程序开发区
请教高手:如何在linux下用mmap映射超大文件,并读取其内容?
我现在有个应用场景,需要在linux下读取超大文件(&2G)的内容,能用mmap映射超大文件吗?
如果我的内存是4G,能映射超过4G的文件吗?
这个映射是不是就是把相应的文件内容复制到内存空间吗?如果是这样,显然占据太多内存是不可行的。
其实我想要的是每次动态映射这个文件一部分,不要超过物理内存的30%,用到哪一部分,动态映射这个文件的相应的一部分,然后读取之,以提高整个文件处理的速度。
windows下有对应的应用场景,但是由于其有特定的API函数支持,而在如何在linux下用mmap映射超大文件,如何动态读取其内容(有什么特定的函数吗)?
请教高手,多多谢了!
manpage里面的东西:
void&*mmap(void&*start,&size_t&length,&int&prot,&int&flags,
&&&&&&&&&&&&&&&&&&int&fd,&off_t&offset);
&&&&&&&The&&mmap()&&function&asks&to&map&length&bytes&starting&at&offset&offset&from&the&file&(or&other&object)&specified&by&the&file&descriptor&fd&into&memory,
就是说,从offset位置开始,把文件fd的length字节映射到地址start上。
如果是64位的应用,4G是没有问题的,32位的应用不能。
引用&1&楼&iisbsd&的回复:manpage里面的东西:
&void&*mmap(void&*start,&size_t&length,&int&prot,&int&flags,
& & & & & & & & & &int&fd,&off_t&offset);
& & & &&The &mmap() &function&asks&to&map&length&bytes&starting&at&offset&offset&from&the&file&(or&other&object)&specified&by&the&file&descriptor&fd&into&memory,
&就是说,从offset位置开始,把文件fd的length字节映射到地址start上。
&如果是64位的应用,4G是没有问题的,32位的应用不能。
谢谢大哥的回复,但这个“映射”到底是个什么概念呢?我有点糊涂。mmap函数是把文件“映射”部分复制到内存了呢?还是仅仅做个纯粹的映射,当想使用映射区域的文件时候,操作系统透明的读取硬盘中对应的文件部分?
我还是要重复一下我的需求,我不想一运行我的程序,系统就超级慢,不管是32位还是64位系统,其实我想要的是每次动态映射这个文件一部分,不要超过物理内存的30%,用到哪一部分,动态映射这个文件的相应的一部分,然后读取之,以提高整个文件处理的速度。是不是我要根据程序的需要,不断的更新mmap()函数的start&和offset参数来映射文件不用的区域呢?
而在某些特殊行业,经常要面对十几GB乃至几十GB容量的巨型文件,而一个32位进程所拥有的虚拟地址空间只有232&=&4GB,显然不能一次将文件映像全部映射进来。对于这种情况只能依次将大文件的各个部分映射到进程中的一个较小的地址空间。这需要对上面的一般流程进行适当的更改:&
1)映射文件开头的映像。&
2)对该映像进行访问。&
3)取消此映像&
4)映射一个从文件中的一个更深的位移开始的新映像。&
5)重复步骤2,直到访问完全部的文件数据。
这是在网上看到的一段话&是支持你说的做法的
引用&2&楼&heima123&的回复:是不是我要根据程序的需要,不断的更新mmap()函数的start&和offset参数来映射文件不用的区域呢?
对的,mmap,操作,munmap,计算新的offset,mmap,……
我不觉得你需要更新start,当然,和你的应用有关系。
http://bbs.chinaunix.net/thread--1.html&
这个帖子说的很清楚,在编译时加上选项,就可以直接用lseek偏移超过4G了。
谢谢各位大哥的回复。
其实我的迷惑还有一点没得到解答:
“这个“映射”到底是个什么概念呢?我有点糊涂。mmap函数是把文件“映射”部分复制到内存了呢?
还是仅仅做个纯粹的映射,不占用内存,而是当想使用所映射区域的文件内容的时候,操作系统透明的读取硬盘中对应的文件部分?”
我是菜鸟,请您指点!
这个映射就是把文件的内容(如果是文件的话)copy到内存相应部分,是会占用内存的;大文件么,最好不要用这种方式处理;mmap主要是在进程,线程间通信时用用;处理文件还是用处理文件的方式来吧;lseek64之类的专门是针对大于4G的文件滴;当然在编译的时候加了&D_LARGEFILE_SOURCE也可以起相同用用滴;
引用&7&楼&hittlle&的回复:这个映射就是把文件的内容(如果是文件的话)copy到内存相应部分,是会占用内存的;大文件么,最好不要用这种方式处理;mmap主要是在进程,线程间通信时用用;处理文件还是用处理文件的方式来吧;lseek64之类的专门是针对大于4G的文件滴;当然在编译的时候加了&D_LARGEFILE_SOURCE也可以起相同用用滴;
mmap好像可以映射一部分的吧?内存映射的功能貌似就是专门针对大文件的吧?
mmap是一种虚拟内存接口.
至于“如果我的内存是4G,能映射超过4G的文件吗?”,
回答是“可以”,映射超过2G/4G的文件与物理内存大小无关。
1.&最简单的就是在64位系统上运行64位程序。&这样文件就可以直接访问了。
2.&如果不幸只有32位系统,或者由于某种原因只能只用32位程序,就只好分段访问文件了。
但是需要系统支持XBS5_ILP32_OFFBIG_CFLAGS。
其实只要看看mmap的原型就知道
void&*mmap(void&*addr,&size_t&len,&int&prot,&int&flags,&int&fildes,&off_t&off);
只要off_t支持4G以上就可以了。
All&implementations&will&support&one&of&the&following&programming&environments&as&a&default.&Implementations&may&support&more&than&one&of&the&following&programming&environments.&Applications&can&use&sysconf()&or&getconf&to&determine&which&programming&environments&are&supported.
--------------------------------------------------------------
Programming&Environment&|Bits&in|Bits&in|Bits&in|Bits&in&
getconf&Name& &&&&&&&&|int& |long&&&|pointer|&off_t
------------------------|-------|-------|-------|-------------
_XBS5_ILP32_OFF32& |32& |32& |32& |32
_XBS5_ILP32_OFFBIG& |32& |32& |32& |&=&64
_XBS5_LP64_OFF64& |32& |64& |64& |64
_XBS5_LPBIG_OFFBIG& |&=&32& |&=&64& |&=&64& |&=&64
--------------------------------------------------------------
引用&9&楼&mymtom&的回复:mmap是一种虚拟内存接口.
&至于“如果我的内存是4G,能映射超过4G的文件吗?”,
&回答是“可以”,映射超过2G/4G的文件与物理内存大小无关。
&1.&最简单的就是在64位系统上运行64位程序。&这样文件就可以直接访问了。
&2.&如果不幸只有32位系统,或者由于某种原因只能只用32位程序,就只好分段访问文件了。
&但是需要系统支持XBS5_ILP32_OFFBIG_CFLAGS。
&其实只要看看mmap的原型就知道
&void&*mmap(void&*addr,&size_t&len,&int&prot,&int&flags,&int&fildes,&off_t&off);
&只要off_t支持4G以上就可以了。
All&implementations&will&support&one&of&the&following&programming&environments&as&a&default.&Implementations&may&support&more&than&one&of&the&following&programming&environments.&Applications&canuse&sysconf()&or&getconf&to&determine&which&programming&environments&are&supported.--------------------------------------------------------------
Programming&Environment|Bits&in|Bits&in|Bits&in|Bits&in&
getconf&Name|int|long|pointer|&off_t------------------------|-------|-------|-------|-------------
_XBS5_ILP32_OFF32|32|32|32|32
_XBS5_ILP32_OFFBIG|32|32|32|&=64
_XBS5_LP64_OFF64|32|64|64|64
_XBS5_LPBIG_OFFBIG|&=32|&=64|&=64|&=64--------------------------------------------------------------http://www.opengroup.org/onlinepubs//xcu/c89.html
嗯,是解决办法,不过感觉,mmap这样用很别扭。
off_t&好像是
&&typedef&unsigned&long&&off_t;
&一般只有4GB吧???
&怀疑ing......
引用&11&楼&hittlle&的回复:off_t&好像是
& &typedef&unsigned&long &off_t;
&&一般只有4GB吧???
&&怀疑ing......
与操作系统和编译器以及编译选项都有关。
弱弱的问一下,mmap中的参数fd如何获得?&超大文件用open函数是打不开的,那么如何获得fd呢?
用open64函数呗
引用&7&楼&hittlle&的回复:这个映射就是把文件的内容(如果是文件的话)copy到内存相应部分,是会占用内存的;大文件么,最好不要用这种方式处理;mmap主要是在进程,线程间通信时用用;处理文件还是用处理文件的方式来吧;lseek64之类的专门是针对大于4G的文件滴;当然在编译的时候加了&D_LARGEFILE_SOURCE也可以起相同用用滴;
楼上说,mmap会将文件拷贝到内存中,如果这样的话,何苦mmap呢?直接读取文件不就好了??
回复mmap映射内存的大小是不是不能超过文件大小?
[问题点数:40分,结帖人wangpeng_118]
本版专家分:0
结帖率 83.08%
CSDN今日推荐
本版专家分:19294
2012年4月 Linux/Unix社区大版内专家分月排行榜第一2012年3月 Linux/Unix社区大版内专家分月排行榜第一2012年2月 Linux/Unix社区大版内专家分月排行榜第一2012年1月 Linux/Unix社区大版内专家分月排行榜第一2011年7月 Linux/Unix社区大版内专家分月排行榜第一2011年6月 Linux/Unix社区大版内专家分月排行榜第一2011年2月 Linux/Unix社区大版内专家分月排行榜第一2011年1月 Linux/Unix社区大版内专家分月排行榜第一
2013年7月 Linux/Unix社区大版内专家分月排行榜第二2012年6月 Linux/Unix社区大版内专家分月排行榜第二2011年5月 Linux/Unix社区大版内专家分月排行榜第二2011年4月 Linux/Unix社区大版内专家分月排行榜第二2011年3月 Linux/Unix社区大版内专家分月排行榜第二2010年10月 Linux/Unix社区大版内专家分月排行榜第二2010年9月 Linux/Unix社区大版内专家分月排行榜第二
2011年9月 Linux/Unix社区大版内专家分月排行榜第三2010年12月 Linux/Unix社区大版内专家分月排行榜第三2010年11月 Linux/Unix社区大版内专家分月排行榜第三2010年9月 C/C++大版内专家分月排行榜第三
本版专家分:368097
2017年 总版技术专家分年内排行榜第一
2014年 总版技术专家分年内排行榜第二
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
本版专家分:0
结帖率 83.08%
匿名用户不能发表回复!|
CSDN今日推荐Everyday is everything!
利用内存映射文件处理大文件(转载)(修改程序版)
----原来作者的程序有些问题,现在文章中的程序已经修改正确---
VC中用内存映射文件处理大文件
摘要:本文通过内存映射文件的使用来对大尺寸文件进行访问操作,同时也对内存映射文件的相关概念和一般编程过程作了较为详细的介绍。
  关键词:内存映射文件;大文件处理;分配粒度
  文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。
  内存映射文件概述
  内存文件映射也是Windows的一种内存管理方法,提供了一个统一的内存管理特征,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问。通过文件映射这种使磁盘文件的全部或部分内容与进程虚拟地址空间的某个区域建立映射关联的能力,可以直接对被映射的文件进行访问,而不必执行文件I/O操作也无需对文件内容进行缓冲处理。内存文件映射的这种特性是非常适合于用来管理大尺寸文件的。
  在使用内存映射文件进行I/O处理时,系统对数据的传输按页面来进行。至于内部的所有内存页面则是由虚拟内存管理器来负责管理,由其来决定内存页面何时被分页到磁盘,哪些页面应该被释放以便为其它进程提供空闲空间,以及每个进程可以拥有超出实际分配物理内存之外的多少个页面空间等等。由于虚拟内存管理器是以一种统一的方式来处理所有磁盘I/O的(以页面为单位对内存数据进行读写),因此这种优化使其有能力以足够快的速度来处理内存操作。
  使用内存映射文件时所进行的任何实际I/O交互都是在内存中进行并以标准的内存地址形式来访问。磁盘的周期性分页也是由操作系统在后台隐蔽实现的,对应用程序而言是完全透明的。内存映射文件的这种特性在进行大文件的磁盘事务操作时将获得很高的效益。
  需要说明的是,在系统的正常的分页操作过程中,内存映射文件并非一成不变的,它将被定期更新。如果系统要使用的页面目前正被某个内存映射文件所占用,系统将释放此页面,如果页面数据尚未保存,系统将在释放页面之前自动完成页面数据到磁盘的写入。
  对于使用页虚拟存储管理的Windows操作系统,内存映射文件是其内部已有的内存管理组件的一个扩充。由可执行代码页面和数据页面组成的应用程序可根据需要由操作系统来将这些页面换进或换出内存。如果内存中的某个页面不再需要,操作系统将撤消此页面原拥用者对它的控制权,并释放该页面以供其它进程使用。只有在该页面再次成为需求页面时,才会从磁盘上的可执行文件重新读入内存。同样地,当一个进程初始化启动时,内存的页面将用来存储该应用程序的静态、动态数据,一旦对它们的操作被提交,这些页面也将被备份至系统的页面文件,这与可执行文件被用来备份执行代码页面的过程是很类似的。图1展示了代码页面和数据页面在磁盘存储器上的备份过程:
图1 进程的代码页、数据页在磁盘存储器上的备份
  显然,如果可以采取同一种方式来处理代码和数据页面,无疑将会提高程序的执行效率,而内存映射文件的使用恰恰可以满足此需求。
对大文件的管理
  内存映射文件对象在关闭对象之前并没有必要撤销内存映射文件的所有视图。在对象被释放之前,所有的脏页面将自动写入磁盘。通过CloseHandle()关闭内存映射文件对象,只是释放该对象,如果内存映射文件代表的是磁盘文件,那么还需要调用标准文件I/O函数来将其关闭。在处理大文件处理时,内存映射文件将表示出卓越的优势,只需要消耗极少的物理资源,对系统的影响微乎其微。下面先给出内存映射文件的一般编程流程框图:
图2 使用内存映射文件的一般流程
  而在某些特殊行业,经常要面对十几GB乃至几十GB容量的巨型文件,而一个32位进程所拥有的虚拟地址空间只有232 = 4GB,显然不能一次将文件映像全部映射进来。对于这种情况只能依次将大文件的各个部分映射到进程中的一个较小的地址空间。这需要对上面的一般流程进行适当的更改:
  1)映射文件开头的映像。
  2)对该映像进行访问。
  3)取消此映像
  4)映射一个从文件中的一个更深的位移开始的新映像。
  5)重复步骤2,直到访问完全部的文件数据。
  下面给出一段根据此描述而写出的对大于4GB的文件的处理代码:
// 选择文件 CFileDialog fileDlg(TRUE, "*.txt", "*.txt", NULL, "文本文件 (*.txt)|*.txt||", this); fileDlg.m_ofn.Flags |= OFN_FILEMUSTEXIST; fileDlg.m_ofn.lpstrTitle = "通过内存映射文件读取数据"; if (fileDlg.DoModal() == IDOK) {
// 创建文件对象
HANDLE hFile = CreateFile(fileDlg.GetPathName(), GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
TRACE("创建文件对象失败,错误代码:%d/r/n", GetLastError());
// 创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hFileMap == NULL)
TRACE("创建文件映射对象失败,错误代码:%d/r/n", GetLastError());
// 得到系统分配粒度
SYSTEM_INFO SysI
GetSystemInfo(&SysInfo);
DWORD dwGran = SysInfo.dwAllocationG
// 得到文件尺寸
DWORD dwFileSizeH
__int64 qwFileSize = GetFileSize(hFile, &dwFileSizeHigh);
qwFileSize |= (((__int64)dwFileSizeHigh) && 32);
// 关闭文件对象
CloseHandle(hFile);
// 偏移地址
__int64 qwFileOffset = 0;
DWORD dwBlockBytes =
while (qwFileSize & 0)
// 映射视图
if (qwFileSize &
dwBlockBytes = (DWORD)qwFileS
LPBYTE lpbMapAddress = (LPBYTE)MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, (DWORD)(qwFileOffset && 32), (DWORD)(qwFileOffset & 0xFFFFFFFF), dwBlockBytes);
if (lpbMapAddress == NULL)
TRACE("映射文件映射失败,错误代码:%d/r/n", GetLastError());
// 对映射的视图进行访问
for(DWORD i = 0; i & dwBlockB i++)
BYTE temp = *(lpbMapAddress + i);
// 撤消文件映像
UnmapViewOfFile(lpbMapAddress);
// 修正参数
qwFileOffset += dwBlockB
qwFileSize -= dwBlockB
// 关闭文件映射对象句柄
CloseHandle(hFileMap);
AfxMessageBox("成功完成对文件的访问"); }
  在本例中,首先通过GetFileSize()得到被处理文件长度(64位)的高32位和低32位值。然后在映射过程中设定每次映射的块大小为1000 倍的分配粒度,如果文件长度小于1000倍的分配粒度时则将块大小设置为文件的实际长度。在处理过程中由映射、访问、撤消映射构成了一个循环处理。其中,每处理完一个文件块后都通过关闭文件映射对象来对每个文件块进行整理。CreateFileMapping()、MapViewOfFile()等函数是专门用来进行内存文件映射处理用的。
下面分别对这些关键函数进行说明:
  1)CreateFile():CreateFile()函数是一个用途非常广泛的函数,在这里的用法并没有什么特殊的地方,但有几点需要注意:一是访问模式参数dwDesiredAccess。该参数设置了对文件内核对象的访问类型,其允许设置的权限可以为读权限GENERIC_READ、写权限GENERIC_WRITE、读写权限GENERIC_READ | GENERIC_WRITE和设备查询权限0。在使用映射文件时,只能打开那些具有可读访问权限的文件,即只能应用GENERIC_READ和 GENERIC_READ | GENERIC_WRITE这两种组合;另一点需要注意的是共享模式参数dwShareMode。该参数定义了对文件内核对象的共享方式,其可能的设置为 FILE_SHARE_READ、FILE_SHARE_WRITE和0,并可对其组合使用。其中,设置为0时不允许共享对象; FILE_SHARE_READ和FILE_SHARE_WRITE分别为在要求只读、只写访问的情况下才允许对象的共享。
  由于通过内存映射文件可以在多个进程间共享数据,因此在进行这种应用时应当考虑dwShareMode参数设置对运行结果的影响。
  2)CreateFileMapping():该函数的作用是创建一个文件映射内核对象,以告知系统文件映射对象需要多大的物理存储器。创建内存映射文件对象对系统资源几乎没有什么影响,也不会影响进程的虚拟地址空间。除了需要用来表示该对象的内部资源之外通常并不用为其分配虚拟内存,但是如果内存映射文件对象是作共享内存之用的话,就要在创建对象时由系统为内存映射文件的使用在系统页文件中保留足够的空间。
  函数第一个参数hFile为标识要映射到进程的地址空间的文件的句柄。虽然由于内存映射文件的物理存储器是来自于磁盘上的文件,而非系统的页文件,使创建内存映射文件就像保留一个地址空间区域并将物理存储器提交给该区域一样。第二个参数为指向文件映射内核对象的 SECURITY_ATTRIBUTES结构的指针,由此来决定子进程能否继承得到返回的句柄。通常为其传递NULL值,以默认的安全属性来禁止返回句柄的被继承。
  接下来的参数用于文件被映射后设定文件映像的保护属性。其可能的取值为PAGE_READONLY、 PAGE_READWRITE和PAGE_WRITECOPY。虽然在创建文件映射对象时,系统并不为其保留地址空间区域,也不将文件的存储器映射到该区域。但是,在系统将存储器映射到进程的地址空间中去时,系统必须确切知道应赋予物理存储器页面的保护属性。在设置保护属性时,必须与用 CreateFile()函数打开文件时所指定的访问标识相匹配,否则将导致CreateFileMapping()的执行失败。因此这里设置 PAGE_READWRITE属性。除了上述三个页面保护属性外,还有4个区(Section)保护属性也可以一起组合使用:
区保护属性
SEC_COMMIT
为区中的所有页面在内存中或磁盘页面文件中分配物理存储器
告知系统,映射的文件是一个可移植的EXE文件映像
SEC_NOCACHE
告知系统,未将文件的任何内存映射文件放入高速缓存,多供硬件设备驱动程序开发人员使用
SEC_RESERVE
对一个区的所有页面进行保留而不分配物理存储器
后面的两个参数指定了要创建的文件映射对象的最大字节数的高32位值和低32位值,实际也就设定了文件的最大字节数(最大可以处理16EB的文件)。这两个参数可以满足确保文件映射对象能够得到足够的物理存储器这一基本条件。在参数设置的大小小于文件实际大小时,系统将从文件映射指定的字节数。这里将其设置为0,将使所创建的文件映射对象将为文件的当前大小,以上两种情况均无法改变文件的大小。如果设置的参数大于文件的实际大小,系统将会在CreateFileMapping()函数返回前扩展该文件。需要指出的是,文件映射对象的大小是静态的,一旦创建完毕后将无法更改。如果设置的文件映射对象尺寸偏小将导致无法对文件进行全面的访问。
  在本节开始也曾提到过,创建文件映射对象是不需要花费什么系统资源的,因此遵循"宁多勿缺"的原则,一般应将文件映射对象的大小设置为文件大小的相同值。函数最后的参数将可以为映射对象命名。如果想打开一个已存在的文件映射对象,该对象必须要命名。对该名字字符串的要求仅限于未被其它对象使用过的名字即可。
3)MapViewOfFile():当创建了一个内存映射文件对象并得到其有效句柄后,该句柄即可用来在进程的虚拟地址空间中映射文件的一个映像。在内存映射文件对象已经存在的情况下,映像可被任意映射或取消映射。在文件映像被映射时,仍然必须由系统来为文件的数据保留一个地址空间区域,并将文件的数据作为映射到该区域的物理存储器进行提交。在进程的地址空间中,一个足够大的连续地址空间(通常足以覆盖整个文件映像)将被指定给此文件映像。尽管如此,内存的物理页面还是根据在实际使用中的需求而进行分配的。真正分配一个对应于内存映射文件映像页面的物理内存页面是在发生该页的缺页中断时进行的,这将在第一次读写内存页面中的任一地址时自动完成。MapViewOfFile()即负责映射内存映射文件的一个映像,
  函数的第一个参数为CreateFileMapping()所返回的内存映射文件对象句柄,第二个参数指定了对文件映像的访问类型,可能取值有FILE_MAP_WRITE、FILE_MAP_READ、FILE_MAP_ALL_ACCESS和 FILE_MAP_COPY等几种,具体的设置要根据文件映射对象允许的保护模式而定。根据前面代码的设置,这里应该使用 FILE_MAP_ALL_ACCESS参数。这种机制为对象的创建者提供了对映射此对象的方式进行控制的能力。接下来的2个参数分别指定了内存映射文件的64位偏移地址的低32位和高32位地址,该地址是从内存映射文件头位置到映像开始位置的距离。最后的参数指定了视图的大小,如果设置为0,前面的偏移地址将被忽略,系统将会把整个文件映射为一个映像。MapViewOfFile()如果成功执行,将返回一个指向文件映像在进程的地址空间中的起始地址的指针。如果失败,则返回NULL。在进程中,可以为同一个文件映射对象创建多个文件映像,这些映像可以在系统中共存和重叠,也可以与对应的文件映射对象大小不相一致,但不能大于文件映射对象的大小。
  4)UnmapViewOfFile():当不再需要保留映射到进程地址空间区域中的文件映像数据时,可通过调用UnmapViewOfFile()函数将其释放。该函数结构非常简单,只需要提供映像在进程中的起始地址(区域的基地址)作为参数即可。该函数的输入参数为调用MapViewOfFile()时所返回的指向文件映像在进程的地址空间中的起始地址的指针。在调用MapViewOfFile()后,必须确保在进程退出之前能够执行UnmapViewOfFile()函数,否则在进程终止之后先前保留的区域将得不到释放,即使再次启动进程重复调用 MapViewOfFile()系统也总是在进程的地址空间中保留一个新的区域,而此前保留的所有区域将得不到释放。
  一种比较特殊的情况是,对同一个内存映射文件映射了两个相同的映像的撤消。前面曾经提到过,对于同一个内存映射文件可以有多个映像,这些映像也可以重叠,因此这种情况的存在是合法的。对于这种情况,虽然从表面看上去在单进程的地址空间内是不可能存在两个基地址完全相同的映像的,这将导致无法对这它们的区分。但是事实上,由MapViewOfFile()所返回得到的基地址只是文件映像在进程地址空间中的起始基地址,因此在映射同一内存映射文件的两个相同映像时将会产生对内存映射文件同一部分的两个不同基地址的相同映像,可以用同样的方法调用 UnmapViewOfFile()将其从进程的地址空间中予以撤消。
  5)CloseHandle():与Win32的大多数对象一样,在使用完毕之后总是要通过 CloseHandle()函数将已打开的内核对象关闭。如果忘记关闭对象,在程序继续运行时将会出现资源泄漏。虽然在程序退出运行时,操作系统会自动关闭在进程中已经打开但未关闭的任何对象。但是在进程的运行过程中,势必会积累过多的资源句柄。因此在不再需要使用对象的时候通过CloseHandle ()将其予以关闭是有意义的。
  本文对内存映射文件在大文件处理中的应用作了较为详细的阐述。经实际测试,内存映射文件在处理大数据量文件时表现出了良好的性能,比通常使用CFile类和ReadFile()和WriteFile()等函数的文件处理方式具有明显的优势。本文所述程序代码在 Windows 2000 Professional下由Microsoft Visual C++ 6.0编译通过。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 c 内存映射文件 的文章

 

随机推荐