转自: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, 000);
        
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++


FeedBack:
# re: 内存映射文件
2009-04-14 11:42 | -274°C
写入:
pFileMap = (FILEMAP*)::MapViewOfFile(g_hFileMap, FILE_MAP_WRITE, 0, 0, 0);
if (pFileMap)
{
pFileMap->hForegroundWnd = hWnd;
bRet = TRUE;
}
::UnmapViewOfFile(pFileMap);  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 

常用链接

留言簿(21)

随笔分类(265)

随笔档案(242)

相册

JAVA网站

关注的Blog

搜索

  •  

积分与排名

  • 积分 - 911937
  • 排名 - 40

最新评论