文件内存映射是一种机制,它允许我们在磁盘上创建一个文件的映射对象。在此之后,不同的进程可以在它们各自的虚拟地址空间中创建这个文件映射对象的视图。一个进程可以在其虚拟地址空间中创建该文件映射对象的一个或多个视图,并对其进行操作。下面展示了文件映射对象的工作原理图:
请务必记住以下几个关键点:
- 文件位于运行进程的计算机磁盘上。
- 文件映射对象位于物理内存中。
- 多个进程可以为同一个文件映射对象创建视图。
- 文件映射对象可以包含整个文件或文件的一部分。同样,进程的文件视图也可以包含整个文件映射对象或其一部分。
- 所有副本都是保持一致的,并且与磁盘上存在的数据完全相同。
优势
- 当处理大型文件(如数据库文件)时,这非常有帮助,因为不需要将整个文件都加载到物理内存中。
- 多个进程可以使用磁盘上的同一个文件进行读写操作。每个进程都可以创建一个新视图,并取消映射当前的文件视图。
创建文件映射对象和文件视图的步骤
步骤 1: 创建或打开一个代表磁盘上文件的文件对象。在这里,我们创建了一个新的文件对象,其句柄为 hFile,命名为 "datafile.txt"。
HANDLE CreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
// 使用方式如下
HANDLE hFile = CreateFile(TEXT("datafile.txt"),
GENERIC_READ | GENERIC_WRITE,
0,
// 以独占访问方式打开
NULL,
// 无安全属性
// 创建一个新的临时文件
CREATE_NEW,
// 在取消映射视图后删除文件
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
HANDLE CreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
// 使用方式如下
HANDLE hFile = CreateFile(TEXT("datafile.txt"),
GENERIC_READ | GENERIC_WRITE,
0, // 以独占访问方式打开
NULL, // 无安全属性
CREATE_NEW, // 创建一个新的临时文件
FILE_FLAG_DELETE_ON_CLOSE, //在取消映射视图后删除文件
NULL);
步骤 2: 为该文件创建一个映射对象,其中包含有关如何访问文件及其大小的信息。因此,在创建上述文件后,我们使用其句柄并在物理内存中创建它的映射。
HANDLE CreateFileMappingA(
HANDLE hFile,
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCSTR lpName
);
// 使用方式如下
HANDLE hFileMapping = ::CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, bufferSize, filename);
步骤 3: 将文件映射对象的全部或一部分从物理内存映射到我们进程的虚拟地址空间。在这里,我们正在创建映射文件的视图,该视图将被进程使用。
LPVOID MapViewOfFile(
HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap
);
// 使用方式如下
void* p = ::MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, param1, param2);
步骤 4: 清理工作
4(A) 从进程地址空间中取消映射文件映射对象。回溯上述步骤,首先,从进程的地址空间中移除文件视图。
BOOL UnmapViewOfFile(LPCVOID lpBaseAddress
);
// 使用方式如下
UnmapViewOfFile(p);
4(B) 关闭文件映射对象。此步骤将从物理内存中移除文件映射。
CloseHandle(hFileMapping);
4(C) 关闭文件对象。在这里,关闭在磁盘上打开的文件并释放句柄。由于在第一步中我们设置了标志 FILEFLAGDELETEONCLOSE,文件将在这一步之后被删除。
CloseHandle(hFile);
> 注意:
>
>
>
> 1. 请按相同的顺序关闭句柄,否则会导致差异或错误。
> 2. 在尝试删除文件之前,请关闭所有打开的文件句柄。