使用内存映射文件的目的有3 个:
(1 )系统使用内存映射文件来加载和执行.EXE 和DLL 文件。这极大的节省了系统页文件空间,也缩短了启动应用程序所需的时间。
(2 )使用内存映射文件访问磁盘上的数据。这既避免了对文件执行文件 I/O(输入/ 输出)操作,也避免了为文件的内容申请缓冲区。
(3 )使用内存映射文件在多个进程间共享数据。Windows 也提供了其他进程间通信的方法——但是这些方法都是使用内存映射文件实现的,所以内存映射文件是最有效的方法。
内 存 映 射 文 件 的 函 数 包 括 CreateFileMapping 、OpenFileMapping、MapViewOfFile、UnmapViewOfFile 和FlushViewOfFile 。 使用内存映射文件可以分为两步,第一步是使用CreateFileMapping 创建一个内存映射文件内核对象,告诉操作系统内存映射文件需要的物理内存大小。这个步骤决定了内存映射文件的用途——究竟是为磁盘上的文件建立内存映射还是为多个进程共享数据建立共享内存。
CreateFileMapping 函数可以创建或者打开一个命名的或未命名的映射文件对象,用法如下。
HANDLE CreateFileMapping(
HANDLE hFile, // 一个文件的句柄
LPSECURITY_ATTRIBUTES lpAttributes, // 定义内存映射文件对象是否可以继承
DWORD flProtect, // 该内存映射文件的保护类型
DWORD dwMaximumSizeHigh, // 内存映射文件的长度
DWORD dwMaximumSizeLow,
LPCTSTR lpName // 内存映射文件的名字
);
函数的第一个参数hFile指定要映射的文件的句柄,如果这是一个已经打开的文件的句柄(CreateFile函数的返回值),那么将建立这个文件的内存映射文件;如果这个参数是-1 ,那么将建立共享内存。 第三个参数flProtect 指定内存映射文件的保护类型,它的取值可以是 PAGE_ READONLY(内存页面是只读的)或PAGE_READWRITE (内存页面可读写)。 dwMaximumSizeHigh和dwMaximumSizeLow 参数组合指定了一个 64 位的内存映射文件的长度。一种简单的方法是将这两个参数全部设置位 0 ,那么内存映射文件的大小将与磁盘上的文件相一致。
如果创建的是共享内存,其他进程不能再使用CreateFileMapping 函数去创建同名的内存映射文件对象,而要使用OpenFileMapping函数去打开已创建好的对象,函数用法如下。
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // 指定保护类型
BOOL bInheritHandle, // 返回的句柄是否可被继承
LPCTSTR lpName // 创建对象时使用的名字
);
dwDesiredAccess参数指定的保护类型有 FILE_MAP_WRITE 和FILE_MAP_READ,分别为可写属性和可读属性。 如果CreateFileMapping 和OpenFileMapping函数执行成功,返回的是内存映射文件句柄;如果函数执行失败则返回NULL。 使用内存映射文件的第二步是映射文件映射对象的全部或者一部分到进程的地址空间。可以认为该操作是为文件中的内容分配线性地址空间,并将线性地址和文件内容对应起来。完成这项操作的函数是MapViewOfFile,它的用法如下。
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 前两个函数返回的内存映射文件对象的句柄
DWORD dwDesiredAccess, // 指定保护类型,可以是FILE_MAP_WRITE、FILE_MAP_READ
DWORD dwFileOffsetHigh, // 从文件的那个地址开始映射
DWORD dwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap // 要映射的字节数,如果指定为0 则映射整个文件
);
如果映射成功,函数返回映射视图的内存地址。失败则返回NULL。 当不使用内存映射文件时,可以通过 UnmapViewOfFile 函数撤销映射并使用CloseHandle函数关闭内存映射文件的句柄。
BOOL UnmapViewOfFile (LPCVOID lpBaseAddress );
如果修改了映射视图中的内存,系统会在试图撤销映射或文件映射对象被删除时自动将数
据写到磁盘上,但程序也可以根据需要将视图中的数据立即写到磁盘上,完成该功能的函数是
FlushViewOfFile 。
BOOL FlushViewOfFile(
LPCVOID lpBaseAddress, // 开始的地址
SIZE_T dwNumberOfBytesToFlush // 数据块的大小
);
#include "iostream"
#include "string.h"
#include "windows.h"
using namespace std;
int main()
{
char* buf = "MySharedMemory";
char* data = "123456";
HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS,0,buf);
char* BufReadWrite;
if (hMap != NULL)
{
cout<<"打开共享内存成功!"<<endl;
BufReadWrite = (char*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
cout<<BufReadWrite<<endl;
}
else
{
hMap = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,strlen(data)+1,buf);
BufReadWrite = (char*)MapViewOfFile(hMap,FILE_MAP_ALL_ACCESS,0,0,0);
strcpy(BufReadWrite,data);
cout<<"写入共享内存成功!"<<endl;
}
UnmapViewOfFile(BufReadWrite);
getchar();
CloseHandle(hMap);
return 1;
}