内存映射文件:最适合管理大的数据流和在多个进程间共享数据
“内存映射文件”与虚似内存相似,内存映射文件允许保留一块地址空间区域和向该区域提交物理存储,这是相同之处。不同点是:它的物理存储来自于磁盘文件,而不是系统的页面文件。一旦文件被成功映射,那么就可以像整个文件被装入内存一样来访问它。
一、使用内存映射文件的目的:
1.系统使用内存映射文件来装入和执行EXE和DLL文件。
2.可以使用内存映射文件来访问磁盘上的数据文件,这样做就不用进行文件I/D操作或缓冲文件的内容。
3.允许远行在同一台计算机上的多个进程共享数据。
二、内存映射EXE和DLL文件时系统所要做的一些事情:
1.系统定位在CreateProcess中指定的EXE文件。
2.系统创建一个新的进程内核对象。
3.系统为新进程创建一个4GB的地址空间。
4.系统在地址空间中保留了足够装下EXE文件的一块区域。该区域的位置由EXE文件中的信息来指定。
5.系统知道该保留区域的物理存储是在磁盘上的EXE文件,而不是系统中的页面文件。
三、系统通过“内存管理系统和写拷贝特性”来管理应用程序对其数据页中的全局变量进行写操作。每当应用程序试图写内存映射文件时,系统会捕捉到该请求,拷贝要写的内存页中的内容到一个新分配的内存空间,然后允许应用程序对该块内存进行写操作。
图中的“实例1”要对它的“数据页2”中的数据进行写操作,为了不影响其它实例对该页的访问,系统使用“内存管理系统和写拷贝特性”来为实例1新分配一个“新页”。图中的新页就是系统为它新分配的一个对应于数据页2 的一个新页(它与数据页2的内容是相同的),实例1就可以对该新页进行写操作了,这样做不会影响实例2对内存中数据2的访问。
四、使用内存映射文件:
要使用内存映射文件必须执行下面几步:
1.创建或打开一个文件内核对象(用来标识磁盘上的想用来做为内存映射文件的文件)。创建或打开一个文件内核对象的方法:使用函数CreateFile,函数的原形:
HANDLE CreateFile(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile);
注意在16位机上使用OpenFile来打开文件,而在32位中都是使用CreateFile来打开文件,但是在32位机上还保留着OpenFile函数,见义在Win32中避免使用OpenFile函数。如果CreateFile成功地打开文件或创建了文件,将返回一个文件句柄,否则将返回INVALID_HANDLE_VALUE。CreateFile是告诉操作系统文件映射的物理存储的位置(如:硬盘上、网络上、CD-ROM上等)。
2.创建一个文件映射内核对象(用于告诉系统文件的大小和访问文件的方法)。创建文件映射内核对象方法:使用CreateFileMapping函数。它的原形如下:
HANDLE CreateFileMapping(HANDLE hFile,LPSECURITY_ATTRIBUTES lpsa,DWORD fdwProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,LPSTR lpszMapName);各参数说明:
hFile:是要映射到进程地址空间的文件句柄。该句柄由CreateFile函数返回。调用CreateFileMapping函数时,必须指定参数fdwProtect ,该参数用于指定保护属性(属性值可以为:PAGE_READONLY、PAGE_READWRITE、PAGE_WRITECOPY等)。参数dwmaximumSizeHigh和dwMaximumSizeLow告诉系统文件的最大字节大小,前一个指定高32位,后一个指定低32位,对于4GB以下的文件,dwmaximumSizeHigh总是为0。参数lpszMapName是文件映射对象的名字。
如果系统不能创建文件映射对象,CreateFileMapping函数将返回NULL。
知识复习资料:PE,Protable executable,是Win32可移植的可执行文件。
下面列举一例来说明CreateFile和CreateFileMapping两个函数的用法:
int WINAPI WinMain(HINSTANCE hinstExe,HINSTANCE hinstExePrev,LPSTR pszCmdLine,int nCmdShow){
HANDLE hfile = CreateFile(“C:MMFTest.dat”,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
HANDLE hfilemap = CreateFileMapping(hfile,NULL,PAGE_READWRITE,0,100,NULL);
CloseHandle(hfilemap);
CloseHandle(hfile);
Return(0);
}
3.告诉系统把文件映射对象的全部或部分映射到进程的地址空间。
在创建完文件映射对象后,还要让系统保留一块地址空间区域,将文件数据作为物理存储提交到该区域。这一过程通过调用函数:MapViewOfFile实现:
LPVOID MapViewOfFile(HANDLE hFileMappingObject,DWORD dwDesiredAccess,DWORD dwFileOffsetHigh,DWORD dwFileOffsetLow,DWORD dwNumberOfBytesToMap);
下面对各个参数依次进行说明:hFileMappingObject标识了文件映射对象的句柄,它是由CreateFileMapping或OpenFileMapping的调用返回的。参数dwDesiredAccess标识了数据可以怎样被访问(该参数值可以为:FILE_MAP_WRITE、FILE_MAP_READ、FILE_MAP_ALL_ACCESS、FILE_MAP_COPY)。
当向进程地址空间映射文件时,不必一次映射整个文件。被映射到进程地址空间的那部分文件被称为视图。当把文件的视图映射到进程的地址空间时,必须指定两件事,一、必须告诉系统,数据文件中的哪个字节应当被映射为视图中的第一个字节。这是通过使用参数dwFileOffsetHigh和dwFileOffsetLow来进行设置的。前者用于存储64位偏移量(因为Win32支持的文件大小为180亿GB,所以偏移量就是64位)中的高32位,后者用于存储低32位。最后一个参数dwNumberOfBypesToMap是用来告诉系统要有多少数据文件要映射到进程地址空间中。如果该值为0那意味着系统将试图将从指定的偏移量开始到文件尾的视图进行映射。
注意:文件的偏移量必须是系统分配单元的整数倍。Win32所分配的单元是64KB。
下面举例说明:
HANDLE hFile,hFileMapping;
BYTE bSomeByte,*pbFile;
……
hFile = CreateFile(lpszName,GENRIC_READ|GENRIC_WRITE,0
,NULL,OPEN_ALAWYS,FILE_ATTRIBUTE_NORMAL,NULL);
hFileMapping = CreateFileMapping(hFile,NULL,PAGE_WRITECOPY,0,0,NULL);
pbFile = (PBYTE)MapViewOfFile(hFileMapping,FILE_MAP_COPY,0,0,0);
bSomeByte = pbFile[0];
pbFile[0] = 0;
pbFile[1] = 0;
UnMapViewOfFile(pbFile);
CloseHandle(hFileMapping);
CloseHandle(hFile);
4.在使用完内存映射文件后要执行下面几步来清除:
1.告诉系统文件映射对象从进程的地址空间解除映射。当不在需要在进程的地址空间区域保留文件的数据映射时,可以使用函数BOOL UnMapViewOfFile(LPVOID lpBaseAddress);来释放该区域。参数lpBaseAddress用于指定要释放区域的基地址。注意:该参数的值必须与调用MapViewOfFile函数所返回的值相同。另外一个需要注意的是:在系统使用文件视图时,由于速度的原因吧,系统缓冲了文件的数据页,系统并没有及时将你对文件视图中的修改写入磁盘。如果想让你对文件视图的修改立即写到磁盘,可以调用函数:FlushViewOfFile来实现。不过,当调用函数UnMapViewOfFile后,系统会自动将你对文件视图的修改写入磁盘,也就是说当你需要手动对文件视图进行写磁盘操作时,才用到函数FlushViewOfFile。该函数的原型为:BOOL FlushViewOfFile(LPVOID lpBaseAddress,DWORD dwNumberOfBytesToFlush);其中参数lpBaseAddress是调用MapViewOfFile时所返回的被映射的视图地址,dwNumberOfBytesToFlush是要写入磁盘的字节数。
2.关闭文件映射内核对象。
3.关闭文件内核对象。
使用CloseHandle函数来关闭各个对象。如果忘记关闭这些对象,就会造成资源句柄。当然,就算你不关闭对象,当进程结束时,系统会自动关闭所有你忘记关闭的对象。下面简单说明一个文件从打开、使用、到关闭这一过程:
HANDLE hFile,hFileMapping;
PVOID pFile;
hFile = CreateFile();//该函数告诉系统“要打开或创建的文件在哪里”
hFileMapping = CreateFileMapping(hFile,….);//告诉系统“要打开或创建的文件有多大”
pFile = MapViewOfFile(hFileMapping,…);//“将文件视图映射到进程的地址空间”
pFile = MapViewOfFile(hFileMapping,…);//“将文件视图映射到进程的地址空间”
//现在就可使用“内存映射文件”了
UnMapViewOfFile(pFile);//释放进程地址空间上的文件映射
CloseHandle(hFileMapping);//关闭文件映射内核对象句柄
CloseHandle(hFile);//关闭文件内核对象句柄
…..
上面这段代码就是使用文件映射的方法来实现“虚似内存”的整个过程。不过有一点需要注意:在调用CreateFileMapping和mapViewOfFile这两个函数时分别增加了文件对象和文件映射对象的引用计数。
在使用内存映射对象时,通常是打开文件,创建文件映射对象,然后使用文件映射对象向进程的地址空间映射一个文件的数据的视图。
五、用内存映射文件处理大文件:如何来处理大于4GB的文件呢?首先,从文件开始处映射文件的一部分得到一个视图,当访问完这块映射文件的视图后,可以对它解除映射,然后从文件的更深的偏移量来映射一个新的视图,继续重复这个过程直到访问完整个文件为止。
六、内存映射文件和一致性:Jeffrey Richer推荐使用CreateFile来打开文件时,指定0做为fdwShareMode参数的值,这样会告诉系统该进程将独立访问文件,其它进程不能访问该文件。只读文件不存在一致性问题。决不应使用内存文件在网络上共享可写的文件,因为系统不能保证数据视图的一致性。
七、内存映射文件和Win32实现:在Windows95和Windows NT下对对内存映射文件实现是不同的。在Windows95下所有进程调用MapViewOfFile返回的地址是相同的,而在Windows NT下是不同的,即使两个进程映射的是同一个文件映射对象的映射视图。
1.使用内存映射文件在进程间共享数据:在Win16位下共享数据太简单了,应用程序经常操纵不属于它的数据,而导制其它应用程序崩溃。不过在Win32下共享数据,实际上都是通过“内存映射文件来实现进程间共享数据”,诸如SendMessage(包括使用SendMessage函数传递Win32的WM_COPYDATA消息)和PostMessage等技术共享数据,其本质上都是使用“内存映射文件的机制来实现的”。使用内存映射文件来共享数据实际上是:让两个或多个进程映射同一个文件对象映射的视图,也就是说进程们在共享同一个物理存储页。
2.下面说明在多个进程间共享文件映射对象的一些技术:
一、使用CreateFileMapping()函数:在调用该函数时,可以为文件映射对象指定一个名字,如果这个名称的文件映射对象不存在的话,系统就会创建一个新的文件映射对象,如果这个名称的文件映射对象已经存在了,那么CreateFileMapping不创建新的文件对象,而是增加这个文件映射对象的使用计数,并返回一个标识该文件映射对象的一个进程相关句柄。
二、使用OpenFileMapping()函数:在使用这个函数前,系统中的某个进程必须调用CreateFileMapping函数来产生一个文件映射对象,之后其它进程才可以使用OpenFileMapping函数来共享数据。该函数返回第一个进程创建的文件映射对象的进程相关句柄。在成功调用OpenFileMapping函数后,就可以使用MapViewOfFile函数或MapViewOfFileEx函数将数据映射到自己进程的地址空间里了。
三、继承:利用一个进程来创建一个可继承的文件映射对象句柄,而后派生出一个新的子进程来继承父进程的文件映射对象句柄。(注:这样子进程的文件映射对象句柄与父进程的文件映射对象句柄是相同的)。创建一个可继承的文件映射对象句柄方法:在调用CreateFileMapping函数时,要指定一个结构SECURITY_ATTRIBUTES,并如下初始化该结构:
SECURITY_ATTRIBUTES sa;
Sa.nLength = sizeof(sa);
Sa.lpSecurityDescriptor = NULL;
Sa.bInheritHandle = True;
hFileMap = CreateFileMapping(hFile,&sa,…);
之后当父进程创建子进程时,它必须在调用CreateProcess时,将其参数fInheritHandle的值设置为TRUE,这样做后就增加文件映射对象的使用计数。新进程可以使用该文件映射对象的句柄了,但是新的进程不知道这个句柄的值是多少。可以发送消息或传递命令行参数来使子进程得到该句柄。
分享到:
相关推荐
内存映射文件是一种高效处理大文件的技术,尤其适用于需要处理大量数据的应用场景。在Windows操作系统中,内存映射文件利用虚拟内存机制,将磁盘上的文件直接映射到进程的地址空间,允许程序以访问内存的方式操作...
在Delphi XE中,内存映射文件是一种高效的数据共享机制,它允许多个进程之间共享数据,而无需通过网络或磁盘I/O进行通信。这种技术尤其适用于需要快速交互的进程间通信(IPC)。以下是对标题和描述中涉及的知识点的...
### 内存映射文件详解 #### 一、概述 内存映射文件是一种高级的数据管理技术,被广泛应用于操作系统及应用程序的设计中。本篇内容基于一份关于“内存映射文件”的学习资料,深入探讨了这一主题的核心概念及其应用...
### vc 内存映射文件知识点详解 #### 一、内存映射文件概念与应用场景 内存映射文件(Memory-Mapped File)是一种特殊的技术手段,主要用于实现文件与内存之间的高效交互。这种技术允许应用程序像访问内存一样直接...
内存映射文件是Windows操作系统提供的一种高效访问大文件的技术,它允许程序将文件直接映射到进程的虚拟地址空间中,使得对文件的操作就像是在操作内存一样。这种技术在处理大文件,特别是需要频繁读取的数据时,比...
Visual C++ .NET 提供了一种高效的方法来解决这个问题,那就是利用内存映射文件(Memory-Mapped Files)。本文将深入探讨如何在Visual C++ .NET环境下使用内存映射文件设计一个能够处理超大文件数据的编辑器。 首先...
利用内存映射文件技术实现进程间通信,自pudn程序员联合开发网下载
内存映射文件(Memory-Mapped File)是C#编程中一种高效的数据访问技术,它允许程序将文件直接映射到进程的虚拟地址空间,从而能够像访问内存一样访问文件内容。这种方式在处理大文件时特别有用,因为它避免了频繁的...
### VC++中使用内存映射文件处理大文件 在计算机编程领域,特别是在处理大量数据时,内存映射技术成为了一种高效的数据访问手段。本文将详细介绍如何在VC++(Visual C++)环境下利用内存映射文件(memory-mapped ...
在这个例子中:我们为内存映射文件定义文件路径 ( filePath) 和大小 ( )。fileSize在本例中,我们正在处理一个 100 MB 的文件。我们使用创建或打开内存映射文件MemoryMappedFile.CreateFromFile。如果该文件不存在,...
### 基于内存映射文件技术的海量影像数据快速读取方法 #### 摘要与背景 随着信息技术和传感器技术的迅速发展,遥感图像的数据量呈现几何级数的增长趋势。传统的文件读取方法(如通过文件指针读取文件)仅能正确...
### 基于内存映射文件技术的海量影像数据快速读取方法 #### 摘要与背景 随着信息技术和传感器技术的迅速发展,遥感图像的数据量正在以惊人的速度增长,从早期的几兆到现今动辄数百兆乃至数十GB的规模。这种巨大的...
内存映射文件(Memory-Mapped File)是一种在操作系统层面实现的高效文件处理技术,它允许程序将文件直接映射到进程的虚拟地址空间中,使得文件数据可以像访问内存一样被读写。这种方式大大简化了大文件处理的过程,...
在本实例中,我们将深入探讨如何使用C++和STL库来读取STL文件,特别关注两种不同的读取方法:普通文件解析和内存映射文件解析,并比较它们的性能差异。 首先,我们来看STL文件的基本结构。每个STL文件由多个三角...
### 使用内存映射文件加快文件操作速度 在计算机科学领域,提高文件操作效率一直是系统优化的重要环节之一。本文将深入探讨如何通过使用内存映射文件(Memory-Mapped Files)来加速文件读写过程,特别是在使用VB...
内存映射文件(Memory-Mapped File)是一种在操作系统层面上高效读写大文件的技术,它允许应用程序将文件的内容直接映射到进程的虚拟地址空间中,使得数据的读写如同操作内存一样快速。这种方式在处理大数据量时尤其...
需要注意的是,由于内存映射文件可能跨越多个页,所以部分写操作可能导致整个页被刷新到磁盘,这可能会有性能影响。 5. 关闭映射:完成操作后,使用`unmap`方法释放内存映射,然后关闭文件。这会确保所有未同步的...
内存映射文件(Memory-Mapped File)是一种在操作系统层面实现高效大数据处理的技术,它允许将文件的内容直接映射到进程的虚拟内存空间中,使得应用程序可以像操作普通内存一样读写文件,从而实现快速的数据存取。...