当前位置: 首页 > news >正文

Windows使用内存映射文件

1.简介

内存映射文件主要用于以下三种情况:

  • 系统使用内存映射文件,以便加载和执行. exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。

  • 可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。

  • 可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。

使用内存映射文件,需要执行下面三个步骤。

  1. 创建或打开一个文件内核对象,该对象标识了我们想要用作内存映射文件的那个磁盘文件。

  2. 创建一个文件映射内核对象,告诉系统该文件的大小和你打算如何访问该文件。

  3. 告诉系统把文件映射对象的部分或全部映射到进程的地址空间中。

当完成对内存映射文件的使用时,必须执行下面这些步骤将它清除:

  1. 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映射。
  2. 关闭文件映射内核对象。
  3. 关闭文件内核对象。

2.示例

步骤1:创建或打开文件内核对象

调用CreateFile来创建或打开一个文件内核对象。

HANDLE CreateFile(
   PCSTR pszFileName,
   DWORD dwDesiredAccess,
   DWORD dwShareMode,
   PSECURITY_ATTRIBUTES psa,
   DWORD dwCreationDisposition,
   DWORD dwFlagsAndAttributes,
   HANDLE hTemplateFile
);

步骤2:创建文件映射内核对象

调用CreateFileMapping函数告诉系统,文件映射内核对象需要多少物理存储器。

HANDLE CreateFileMapping(
   HANDLE hFile,
   PSECURITY_ATTRIBUTES psa,
   DWORD fdwProtect,
   DWORD dwMaximumSizeHigh,
   DWORD dwMaximumSizeLow,
   PCTSTR pszName
);
  • hFile:用于标识你想要映射到进程地址空间中的文件句柄。该句柄由前面调用的CreateFile函数返回。
  • psa:参数是指向文件映射内核对象的SECURITY_ATTRIBUTES结构的指针。
  • fdwProtect:使你能够设定这些保护属性。大多数情况下,可以设定下面列出的3个保护属性之一。
  • 第四和五个参数:dwMaximumSizeHigh和dwMaximumSizeLow这两个参数将告诉系统该文件的最大字节数。
  • pszName:该名字用于与其他进程共享文件映射对象。

保护属性:

  • PAGE_READONLY:当文件映射对象被映射时,可以读取文件的数据。必须已经将GENERIC_READ传递给CreateFile函数
  • PAGE_READWRITE:当文件映射对象被映射时,可以读取和写入文件的数据。必须已经将GENERIC_READ | GENERIC_WRITE传递给CreateFile
  • PAGE_WRITECOPY:当文件映射对象被映射时,可以读取和写入文件的数据。如果写入数据,会导致页面的私有拷贝得以创建。必须已经将GENERIC_READ或GENERIC_WRITE传递给CreateFile。

步骤3:将文件的数据映射到进程的地址空间

将文件的数据作为映射到该区域的物理存储器进行提交。

PVOID MapViewOfFile(
   HANDLE hFileMappingObject,
   DWORD dwDesiredAccess,
   DWORD dwFileOffsetHigh,
   DWORD dwFileOffsetLow,
   SIZE_T dwNumberOfBytesToMap
);
  • hFileMappingObject:于标识文件映射对象的句柄,该句柄是前面调用CreateFileMapping或OpenFileMapping函数返回的。
  • dwDesiredAccess:标识如何访问该数据。
  • 第三四个参数:dwFileOfsetHigh和dwFileOfsetLow参数。指定哪个字节应该作为视图中的第一个字节来映射。
  • dwNumberOfBytesToMap:有多少字节要映射到地址空间。如果设定的值是0,那么系统将设法把从文件中的指定位移开始到整个文件的结尾的视图映射到地址空间。

步骤4:从进程的地址空间中撤消文件数据的映像

BOOL UnmapViewOfFile(PVOID pvBaseAddress);
  • pvBaseAddress由MapViewOfFile函数返回。

如果没有调用这个函数,那么在进程终止运行前,保留的区域就不会被释放。每当调用MapViewOfFile时,系统总是在你的进程地址空间中保留一个新区域,而以前保留的所有区域将不被释放。

为了提高速度,系统将文件数据的页面进行缓存处理,这样在处理文件映射视图的时候就不需要随时更新磁盘上的文件。如果需要确保你的更新被写入磁盘,可以强制系统将修改过的数据的一部分或全部重新写入磁盘映像中,方法是调用FlushViewOfFile函数:

BOOL FlushViewOfFile(
   PVOID pvAddress,
   SIZE_T dwNumberOfBytesToFlush
);
  • 第一个参数是包含在内存映射文件中的视图的一个字节的地址。该函数会把传入的地址向下取整到页面大小的整数倍。
  • 第二个参数用于指明你想要刷新的字节数。系统将把这个数字向上取整,使得总字节数是页面大小的整数倍。如果你调用FlushViewOfFile函数并且不修改任何数据,那么该函数只是返回,而不将任何信息写入磁盘。

步骤5:关闭文件映射对象和文件对象

HANDLE hFile = CreateFile(...);

HANDLE hFileMapping = CreateFileMapping(hFile, ...);

CloseHandle(hFile);

PVOID pvFile = MapViewOfFile(hFileMapping, ...);

CloseHandle(hFileMapping);

// Use the memory-mapped file.

UnmapViewOfFile(pvFile);

源码:

#include <iostream>
#include <windows.h>
#include <iostream>
using namespace std;

int main()
{
	// 自己创建一个test.txt文件,并写入内容
	HANDLE hFile = CreateFile(L"D:\\test.txt",GENERIC_READ | GENERIC_WRITE,
		0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

	// Create a file-mapping object for the file.
	HANDLE hFileMapping = CreateFileMapping(hFile,
	NULL,
	PAGE_WRITECOPY,
	0, 0,
	NULL);

	PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_COPY, 0, 0, 0);

	cout << pbFile << endl;

	UnmapViewOfFile(pbFile);
	CloseHandle(hFileMapping);
	CloseHandle(hFile);

	return 0;
}

相关文章:

  • 基于Matlab使用激光雷达检测分类跟踪车辆仿真(附源码)
  • 火狐浏览器 优化教程
  • 计算机的发展史,让你想到了什么?
  • 记一次SQL注入的收获
  • 大数据必学Java基础(八十):网络编程的深入了解
  • 建议收藏丨你想了解的动捕内容全在这儿!
  • 基于蚂蚁-遗传优化算法的路径规划问题(Matlab代码实现)
  • 【数据结构】-----二叉树(递归、层次实现二叉树的遍历)
  • Spring MVC 请求处理过程。你这样回答保证通过面试!
  • 两台电脑mysql数据迁移,各版本mysql迁移(亲测)
  • MD5退出历史舞台你知道吗?
  • 使用nw.js将web项目打包为exe软件(xp版本)
  • 我,在日本开密室逃脱,钱还没赚,人进“橘子”了……
  • “池化技术” - 深度剖释底层内存管理细节,明晰“池化技术”内存管理技术
  • 【网站架构】Tomcat长时间运行崩溃?Tomcat调优、集群
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Java IO学习笔记一
  • JavaScript设计模式之工厂模式
  • java第三方包学习之lombok
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • MYSQL 的 IF 函数
  • PermissionScope Swift4 兼容问题
  • PHP 7 修改了什么呢 -- 2
  • React-生命周期杂记
  • Spark RDD学习: aggregate函数
  • Vue官网教程学习过程中值得记录的一些事情
  • 半理解系列--Promise的进化史
  • 给Prometheus造假数据的方法
  • 使用 @font-face
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​批处理文件中的errorlevel用法
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • ### RabbitMQ五种工作模式:
  • #### go map 底层结构 ####
  • #QT 笔记一
  • (003)SlickEdit Unity的补全
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (SpringBoot)第二章:Spring创建和使用
  • (WSI分类)WSI分类文献小综述 2024
  • (zhuan) 一些RL的文献(及笔记)
  • (ZT)一个美国文科博士的YardLife
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (离散数学)逻辑连接词
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)插入排序
  • (转)德国人的记事本
  • (转载)虚函数剖析
  • **《Linux/Unix系统编程手册》读书笔记24章**
  • .NET 分布式技术比较
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .Net--CLS,CTS,CLI,BCL,FCL