转自:http://www.zxbc.cn/html/20080524/51094.html
与虚拟内存一样,内存映射文件可以用来保留一个地址空间的区域,一旦该文件被映射,就可以访问它,就像整个文件已经加载内存一样。
内存映射文件可以用于3个不同的目的:
1. 系统使用内存映射文件,以便加载和执行exe 和dll文件,这可以大大节省页文件空间和应用程序启动运行所需的时间。
2.可以使用内存映射文件来访问磁盘上的数据文件,这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。
3.可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据,Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上多个进程互相进行同行的最有效的方法。
一.内存映射文件的函数包括
CreateFileMapping , OpenFileMapping, MapViewOfFile, UnmapViewOfFile
和
FlushViewOfFile
。
用法如下:
1
.
HANDLE CreateFileMapping(
HANDLE hFile, //
一个文件句柄
LPSECURITY_ATTRIBUTE lpAttributes, //
定义内存映射文件对象是否可以被承
DWORD flProtect, //
该内存映射文件的保护类型
DWORD dwMaximumSizeHigh,//
内存映射文件的长度
DWORD dwMaximumSizeLow, //
LPCTSTR lpName //
内存映射文件的名字
)
hFile
指定要映射的文件的句柄,如果这是一个已经打开的文件的句柄(
CreateFile
函数的返回值),那么将建立这个文件的内存映射文件,如果这个参数为
-1
,则建立共享内存。
lpAttribute
安全属性,一般设为
NULL
flProtect
指定映射文件的保护类型,它的取值可以是
PAGE_READONLY
(内存页面只读)
或
PAGE_READWRITE
(内存页面可读写)。
dwMaximumSizeHigh
和
dwMaximumSizeLow
参数组合指定了一个
64
位的内存映射文件的长度。一种简单的方法是将这两个参数全部设置为
0
,那么内存映射文件的大小将与磁盘文件大小一致。
2
.
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, //
指定保护类型
BOOL bIsInheritHandle, //
返回的句柄是否可以被继承
LPCSTR lpName //
创建对象时使用的名字
)
如果创建的是共享内存,其他进程不能再使用
CreateFileMapping
函数去创建同名的内存映射文件对象,而要使用
OpenFileMapping
函数打开已创建好的对象。
dwDesiredAcess
指定保护类型有
FILE_MAP_WRITE
或
FILE_MAP_READ
3
.
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, //
前两个函数返回的内存映射文件的句柄
DWORD dwDesiredAcess, //
保护类型
FILE_MAP_READ ,FILE_MAP_WRITE
DWORD dwFileOffsetHight, //
从文件的那个地址开始映射
DWORD dwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap //
要映射的字节数,为
0
则映射整个文件
)
4
.
BOOL UnmapViewOfFile( LPCVOID lpBaseAddress )
当不再使用内存映射文件时,可以通过
UmmapViewOfFile
函数撤销映射并使用
CloseHandle
函数关闭内存映射文件的句柄。
5
.
BOOL FlushViewOfFile(
LPCVOID lpBaseAddress, //
开始的地址
SIZE_T dwNumberOfBytesToFlush //
数据块的大小
)
如果修改了映射视图中的内存,系统会在试图撤销映射或文件映射对象被删除时自动将数据写到磁盘上,但程序也可以根据需要将视图中的数据立即写到磁盘上。
二.使用步骤
1.
使用
CreateFileMapping
创建一个内存映射文件内核对象,告诉操作系统内存映射文件需要的物理内存大小,这个步骤决定了内存映射文件的用途――究竟是为磁盘上的文件建立内存映射还是为多个进程共享数据建立共享内存。或者使用
OpenFileMapping
打开映射文件内核对象。
2.
映射文件映射对象的全部或一部分到进程的地址空间,可以认为该操作是为文件中的内容分配线型地址空间,并将线型地址和文件内容对应起来,完成该操作的函数是
MapViewOfFile
。
三.使用内存映射文件读文件的具体过程可以这样:
(1)
调用
CreateFile
函数打开想要映射的文件,得到文件句柄
hFile
。
(2)
调用
CreateFileMapping
函数,并传入文件句柄
hFile
,为该文件创建一个内存映射内核对象,得到内存映射文件的句柄
hMap
。
(3)
调用
MapViewOfFile
函数映射整个文件或一部分到进程的虚拟地址空间。该函数返回文件映射到内存后的起始地址。使用指向这个地址的指针就可以读取文件的内容了。
(4)
调用
UnmapViewOfFile
函数来解除文件映射。
(5)
调用
CloseHandle
函数关闭文件对象,必须传入内存映射文件句柄
hMap
(6)
调用
CloseHandle
函数关闭文件对象,必须传入文件句柄
hFile
。
四.进程间共享内存:
共享内存主要是通过映射机制实现的。
Windows
下进程的地址空间是相互隔离的,但在物理上却是重叠的。所谓的重叠是指同一块内存区域可能被多个进程同时使用。当调用
CreateFileMapping
创建命名的内存映射文件对象时,
Windows
即在物理内存中申请了一块指定大小的内存区域,返回文件映射对象的新句柄
hMap
。为了能够访问这块区域必须调
MapViewOfiFile
函数,促使
Windows
将此内存空间映射到进程的地址空间中。当在其他进程中访问这块区域时,则必须使用
OpenFileMapping
函数来取得对象句柄
hMap
,并调用
MapViewOfFile
函数得到此内存空间的一个映射。这样一来,系统就把同一块内存区域映射到了不同进程的地址空间中,从而达到共享内存的目的。
一段实例代码:
BOOL bRet = TRUE;
HANDLE hMapFile = NULL;
FILEMAP* pFileMap = NULL;
g_hFileMap = ::CreateFileMapping(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof(FILEMAP),
g_FileMapFlag);
if (g_hFileMap && ERROR_ALREADY_EXISTS == ::GetLastError())
{
pFileMap = (FILEMAP*)::MapViewOfFile(g_hFileMap, FILE_MAP_READ, 0, 0, 0);
if (pFileMap)
{
ATLASSERT(::IsWindow(pFileMap->hForegroundWnd));
::PostMessage(pFileMap->hForegroundWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
::SetForegroundWindow(pFileMap->hForegroundWnd);
bRet = FALSE;
}
::UnmapViewOfFile(pFileMap);
}
posted on 2009-04-14 00:34
-274°C 阅读(1541)
评论(1) 编辑 收藏 所属分类:
C++