内存映射文件

和虚拟内存一样,内存映射文件可以用来保留一个进程地址区域;但是,与虚拟内存不同,它提交的不是物理内存或是虚拟页文件,而是硬盘上的文件。将文件映射成内存,我们可以像使用内存一样使用文件.

使用场合

它有三个主要用途:

系统加载EXE和DLL文件

操作系统就是用它来加载exe和dll文件建立进程,运行exe。这样可以节省页文件和启动时间。

访问大数据文件

如果文件太大,比如超过了进程用户区2G,用fopen是不能对文件进行操作的。这时,可用内存映射文件。对于大数据文件可以不必对文件执行I/O操作,不必对所有文件内容进行缓存。

进程共享机制

内存映射文件是多个进程共享数据的一种较高性能的有效方式,它也是操作系统进程通信机制的底层实现方法。RPC、COM、OLE、DDE、窗口消息、剪贴板、管道、Socket等都是使用内存映射文件实现的。

相关函数介绍

CreateFile(文件名,访问属性,共享模式,…)

作用:创建文件内核对象API

其中,访问属性有:

0 不能读写 (用它可以访问文件属性)

GENERIC_READ

GENERIC_WRITE

GENERIC_READ|GENERIC_WRITE;

共享模式:

0 独享文件,其他应用程序无法打开

FILE_SHARE_WRITE

FILE_SHARE_READ|FILE_SHARE_WRITE

这个属性依赖于访问属性,必须和访问属性不冲突。

当创建失败时,返回INVALID_HANDLE_VALUE。

HANDLE CreateFileMapping(Handle 文件,PSECURITY_ATTRIBUTES 安全属性,DWORD 保护属性,DWORD 文件大小高32位,DWORD 文件大小低32位,PCTSTR  映射名称)

作用:创建文件映射内核对象

“文件”是上面创建的句柄;

“安全属性”是内核对象需要的,NULL表示使用系统默认的安全属性;“保护属性”是当将存储器提交给进程空间时,需要的页面属性:PAGE_READONLY, PAGE_READWRITE和PAGE_WRITECOPY。这个属性不能和文件对象的访问属性冲突。除了这三个外,还有两个属性可以和它们连接使用(|)。当更新文件内容时,不提供缓存,直接写入文件,可用SEC_NOCACHE;当文件是可执行文件时,系统会根据节赋予不同的页面属性,可用SEC_IMAGE。另外,SEC_RESERVE和SEC_COMMIT用于稀疏提交的文件映射,详细介绍请参考下文。

“文件大小高32位”和“文件大小低32位”联合起来告诉系统,这个映射所能支持的文件大小(操作系统支持264B文件大小);当这个值大于实际的文件大小时,系统会扩大文件到这个值,因为系统需要保证进程空间能完全被映射。值为0默认为文件的大小,这时候如果文件大小为0,创建失败。

“映射名称”是给用户标识此内核对象,供各进程共享,如果为NULL,则不能共享。

对象创建失败时返回NULL。

创建成功后,系统仍未为文件保留进程空间。

PVOID MAPViewOfFile(HANDLE 映射对象,DWORD访问属性,DWORD 偏移量高32位,DWORD 偏移量低32位,SIZE_T 字节数)

作用:文件映射内核对象映射到进程空间

“映射对象”是前面建立的对象;

“访问属性”可以是下面的值:FILE_MAP_WRITE(读和写)、FILE_MAP_READ、FILE_MAP_ALL_ACCESS(读和写)、FILE_MAP_COPY。当使用FILE_MAP_COPY时,系统分配虚拟页文件,当有写操作时,系统会拷贝数据到这些页面,并赋予PAGE_READWRITE属性。

可以看到,每一步都需要设置这类属性,是为了可以多点控制,试想,如果在这一步想有多种不同的属性操作文件的不同部分,就比较有用。

“偏移高32位”和“偏移低32位”联合起来标识映射的开始字节(地址是分配粒度的倍数);

“字节数”指映射的字节数,默认0为到文件尾。

当你需要指定映射到哪里时,你可以使用:

PVOID MAPViewOfFile(HANDLE 映射对象,DWORD访问属性,DWORD 偏移量高32位,DWORD 偏移量低32位,SIZE_T 字节数,PVOID 基地址)

“基地址”是映射到进程空间的首地址,必须是分配粒度的倍数。

BOOL FlushViewOfFile(PVOID 进程空间地址,SIZE_T 字节数)

作用:保存文件修改,为了提高速度,更改文件时可能只更改到了系统缓存,这时,需要强制保存更改到硬盘,特别是撤销映射前。

“进程空间地址”指的是需要更改的第一个字节地址,系统会变成页面的地址;

“字节数”,系统会变成页面大小的倍数。

写入磁盘后,函数返回,对于网络硬盘,如果希望写入网络硬盘后才返回的话,需要将FILE_FLAG_WRITE_THROUGH参数传给CreateFile。

当使用FILE_MAP_COPY建立映射时,由于对数据的更改只是对虚拟页文件的修改而不是硬盘文件的修改,当撤销映射时,会丢失所做的修改。如果要保存,怎么办?

你可以用FILE_MAP_WRITE建立另外一个映射,它映射到进程的另外一段空间;扫描第一个映射的PAGE_READWRITE页面(因为属性被更改),如果页面改变,用MoveMemory或其他拷贝函数将页面内容拷贝到第二次映射的空间里,然后再调用FlushViewOfFile。当然,你要记录哪个页面被更改。

BOOL  UnmapViewOfFile(PVOID pvBaseAddress)

作用:撤销映射,pvBaseAddress 这个地址必须与MapViewOfFile返回值相同。

CloseHandle(HANDLE)

作用:关闭内核对象

在不需要内核对象时,尽早将其释放,防止内存泄露。由于它们是内核对象,调用CloseHandle(HANDLE)就可以了。

在CreateFileMapping后马上关闭文件句柄;

在MapViewOfFile后马上关闭内存映射句柄;

最后再撤销映射。

内存映射文件的使用步骤

2.1 创建或打开一个文件
    CreateFile
    2.2 创建内存映射文件
      HANDLE CreateFileMapping(
  HANDLE hFile, //文件句柄
      LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
                             //安全属性
      DWORD flProtect, //保护模式
      DWORD dwMaximumSizeHigh,//大小的高32位
      DWORD dwMaximumSizeLow,    //大小的低32位
      LPCTSTR lpName ); //文件映射内核对象的名称
    2.3 映射成内存地址
    LPVOID MapViewOfFile(
       HANDLE hFileMappingObject, //文件映射句柄
       DWORD dwDesiredAccess, //访问模式
       DWORD dwFileOffsetHigh, //地址偏移高32位
       DWORD dwFileOffsetLow,//地址偏移低32位
       DWORD dwNumberOfBytesToMap ); //要映射的字节数

2.4 使用内存

对于大文件,可以用多次映射的方法达到访问的目的。有点像AWE技术。

Windows只保证同一文件映射内核对象的多次映射的数据一致性,比如,当有两次映射同一对象到二个进程空间时,一个进程空间的数据改变后,另一个进程空间的数据也会跟着改变;不保证不同映射内核对象的多次映射的一致性。所以,使用文件映射时,最好在CreateFile时将共享模型设置为0独享,当然,对于只读文件没这个必要。

2.5 卸载映射
       BOOL UnmapViewOfFile(
   LPCVOID lpBaseAddress //卸载的地址
       );
    2.6 关闭内存映射文件
       CloseHandle
    2.7 文件关闭
       CloseHandle

示例代码:

#include "stdafx.h"
#include "windows.h"void Map( )
{   //创建文件HANDLE hFile = CreateFile( "C:\\map.dat",GENERIC_READ|GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL );//创建文件映射HANDLE hMap = CreateFileMapping( hFile, NULL,PAGE_READWRITE, 0, 1024 * 1024, NULL );//映射地址CHAR * pszText = (CHAR *)MapViewOfFile( hMap, FILE_MAP_ALL_ACCESS,0, 0, 1024 * 1024 );//使用内存strcpy( pszText, "Hello File Mapping" );printf( "%s\n", pszText );//卸载地址UnmapViewOfFile( pszText );//关闭文件映射CloseHandle( hMap );//关闭文件CloseHandle( hFile );
}int main(int argc, char* argv[])
{Map( );return 0;
}

使用windows内存-内存映射文件相关推荐

  1. 修改windows的主机映射文件(hosts文件)

    修改windows的主机映射文件(hosts文件)可以用于xshell进行连接虚拟机时的ip地址,就不需要记住ip地址,而只需要记住主机名即可. 如果操作系统是window10,先拷贝出来,修改保存以 ...

  2. Boost.Interprocess.file_mapping内存映射文件

    什么是内存映射文件? 文件映射是文件内容与进程地址空间的一部分的关联.系统创建一个文件映射关联文件和进程的地址空间.映射区域是进程用来访问文件内容的地址空间的一部分.一个文件映射可以有多个映射区域,以 ...

  3. windows笔记-内存映射文件

    Windows提供了3种进行内存管理的方法: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据. ...

  4. java 内存映射文件进程间通讯_[转]Windows环境下利用“共享内存”实现进程间通信的C/C++代码---利用CreateFileMapping和MapViewOfFile...

    进程间的通信方式有很多种, 上次我们说了最傻瓜的"共享外存/文件"的方法. 那么, 在本文中, 我们即将学习"共享内存"的方式实现进程间的通信, 这是IPC最快 ...

  5. Windows核心编程 第十七章 -内存映射文件(下)

    17.3 使用内存映射文件 若要使用内存映射文件,必须执行下列操作步骤: 1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件. 2) 创建一个文件映射内核对象,告诉系统该 ...

  6. Windows核心编程 第十七章 -内存映射文件(上)

    第1 7章 内存映射文件 对文件进行操作几乎是所有应用程序都必须进行的,并且这常常是人们争论的一个问题.应用程序究竟是应该打开文件,读取文件并关闭文件,还是打开文件,然后使用一种缓冲算法,从文件的各个 ...

  7. 《windows核心编程》 17章 内存映射文件

    内存映射文件主要用于以下三种情况: 系统使用内存映射文件载入并运行exe和dll,这大量节省了页交换文件的空间以及应用程序的启动时间 开发人员可以使用内存映射文件来访问磁盘上的数据文件.这使得我们可以 ...

  8. 内存映射文件——Windows核心编程学习手札之十七

    内存映射文件 --Windows核心编程学习手札之十七 与虚拟内存一样,内存映射文件保留地址空间,并将物理存储器提交给该区域,差别在于所提交的物理存储器是磁盘上有文件存在的空间,而非系统的页文件,一旦 ...

  9. 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件

    本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...

  10. Windows之内存映射文件

    =====================Windows之内存映射文件===================== 几乎每个应用程序都要处理文件,但要处理好并不容易.应用程序到底是先应该打开文件.再读取 ...

最新文章

  1. MongoDB使用小结:一些常用操作分享
  2. java采集温湿度水浸_配电室水浸及温湿度监测系统可加强环境保障
  3. 看完这篇文章你还敢说你懂JVM吗?
  4. Oracle入门(二)之服务启动bat
  5. navigator.geolocation的应用 - 将定位信息显示在百度地图上
  6. html设置表格和div的距离,CSS/HTML Div调整大小和表格定位
  7. [Err] 1231 - Variable 'sql_mode' can't be set to the value of 'NULL
  8. 设计模式之单例模式8种实现方式,其三:懒汉式(线程不安全)
  9. Microsoft Dynamics 365 之 味全食品 项目分享和Customer Engagement新特性分享
  10. java 删除指定文件夹和下面所有文件_JAVA语言基础
  11. H264 STAP-A解包代码(测试通过)
  12. Vmware15虚拟机安装win7镜像
  13. 排队论模型及MATLAB实现
  14. 【R语言】结巴分词与词性提取(以“提取知乎问题标题的频繁词前100个形容词”实战为例)(3月25日学习笔记)
  15. 如何用js实现数组倒序输出
  16. Python用socket、多线程实现一对一聊天室
  17. c语言分段函数x2-sinx,大学高等数学: 第二章第五讲三种分段函数求导法, 再也不担心了...
  18. c语言实现简单的24点游戏
  19. Python绘制3D图形:Axes3D
  20. git使用meld的方法

热门文章

  1. SSM框架运行原理以及流程
  2. 电梯控制系统设计(PLC及组态)
  3. linux下redis常用命令
  4. js 正则表达式判断非法字符以及常用正则表达式。
  5. kali msfconsole命令详解以及靶机攻破实战
  6. 通俗地理解贝叶斯公式(定理)
  7. 未转变者3.16进不去服务器,未转变者3.16.0.1
  8. 小程序 图片上传php后台,微信小程序上传图片到php服务器的方法
  9. 编译protoc方法名称被自动大写
  10. Centos7安装maven