第一章:源起 

遇到一个问题,如果一个客户数据文件有2g大,客户要通过界面查询文件中的数据并用列表控件显示数据,要怎么处理这个文件才能让应用程序不会长时间无响应,客户感觉不到程序的卡顿?

第二章:解决之道

第一反应是用内存映射文件处理大文件,将文件分成数次映射至内存地址空间,避免一次性缓冲整个文件带来的界面长时间无响应,并将暂时不用的内存映射文件取消映射,客户是用列表控件进行显示,那就可以在首次加载的时候只加载第一页的内容就进行显示,之后在缓冲下一页的内容,当用户查看中间页面的内容时可以缓冲将当前页面的上下页面和首页、最后页面对应的文件加载至进程地址空间中,其他的文件映射视图取消映射。

进一步完善创建多线程处理,主线程创建文件映射内核对象,多个子线程分别映射磁盘文件的一部分至进程地址空间并进行数据分析,处理完数据的线程通过SendMessage或者PostMessage又或者锁、关键段、内核线程同步方式等通知界面线程,而界面线程再做一些NOT WAIT操作,添加两个进度条提示首页加载进度和整体文件加载进度,首页加载完成时隐藏进度条并显示数据。

      第三章:正文

      3A:内存映射文件介绍:

创建内存映射文件相当于先调拨一块地址空间区域,然后给区域调拨物理存储器。不同之处在于内存映射文件的物理存储器来自于磁盘上的文件,而不是从系统的页交换文件中分配的。

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

1.系统使用内存映射文件来载入并运行.exe和动态链接库(.dll)文件,可以节省页交换文件的空间和应用程序启动的时间。

2.开发人员可以用内存映射文件来访问磁盘上的数据文件,使得我们可以避免直接对文件进行IO操作和对文件内容进行缓存。

3.通过内存映射文件,我们可以在同一台机器的不同进程之间共享数据,windows也提供了其他一些方式来在进程间传送数据,但这些方法都是通过内存映射文件包装而成,因此最快的同一台机器上的进程间共享数据方法就是内存映射文件。

3C:常用API

CreateFile:打开文件内核对象

CreateFileMapping:创建一个指定名称的文件映射内核对象,通过参数指定映射到进程地址空间的文件句柄。

OpenFileMapping:打开一个指定名称的文件映射内核对象。

MapViewOfFile:把文件数据映射到进程地址空间,通过参数指定映射到进程地址空间的文件映射句柄和文件访问方式。

FlushViewOfFile:处于速度上的考虑,系统会对文件数据的页面进行缓存处理,这样在处理文件映射视图时就不需要随时更新磁盘上的文件,调用FlushViewOfFile将文件映象的修改立即从高速缓存写入磁盘映象。

对内存映射文件的处理类似读取到内存中的文件,或者理解成操作一串字符串。

UnMapViewOfFile:完成文件数据映象的释放。

CloseHandle,关闭文件映射内核对象,关闭文件内核对象,要调用两次。

 3D:注意事项:

可以对同一个文件创建多个内存映射文件,但系统并不保证多个内存映射文件之间的数据一致性,系统只保证同一个内存映射文件的多个视图数据一致。

用作内存映射文件的磁盘文件最好是只读属性,可以避免其他进程对文件修改二造成的映射文件和磁盘文件的不一致,如果无法确认文件是只读的,那么在创建文件对象的CreateFile时指定访问权限为独占。

不应该用内存映射文件来跨网络共享可写文件,系统无法知晓网络上另外一台电脑对文件的操作而继续使用内存中的原始数据。

内存映射文件不一定需要磁盘文件,也可以创建以页交换文件为后备存储器的内存映射文件。与创建以磁盘文件为物理存储器的内存映射文件不同的步骤是:不需CreateFile步骤,在CreateFileMapping时文件内核对象传参INVALID_HANDLE_VALUE,这就告诉系统物理存储设备从页交换文件分配而不是磁盘文件。

    第四章:补充话题:

    4A:稀疏调拨的内存映射文件

之前的内存映射文件要么从磁盘上的数据文件中调拨,要么从页交换文件中调拨,这意味着对存储器的使用可能并不如我们希望的那么高效。按照jeffrey大神的例子,有一个电子表格文件定义:

CELLDATA CellData[200][256];如果CELLDATA的大小是128字节,那么这个数组就需要6553600字节的物理存储器,这也就表示程序开始运行就需要从页交换文件中分配大量的物理存储器,但是用户通常只用前面几个单元格存放信息,绝大多数的单元格都是浪费的。

我们希望把电子表格作为文件映射对象来共享,但又不想一开始就分配这么大的物理存储器,但是采用文件分片映射视图的方式编程会很繁琐,此时我们可以采用稀疏文件映射方式。

稀疏调拨的内存映射文件方法:

CreateFileMapping的fdwProtect参数中指定SEC_RESERVE或SEC_COMMIT,这两个标记只有在以页交换文件为后备存储器来创建文件映射对象时才有意义,SEC_COMMIT标志让CreateFileMapping从页交换文件中调拨存储器。

如果在调用CreateFileMapping的时候传入SEC_RESERVE标志,那么系统不会从页交换文件中调拨屋里存储器,它只返回文件映射对象的句柄。

MapViewOfFile给指定的文件映射对象创建一个视图,即预定一块地址空间区域,但不会给该区域调拨任何物理存储器,此时访问该区域的操作都是非法的。

调用VirtualAlloc给共享区域调拨物理存储器,我们可以只调拨部分存储器给MapViewOfFile预定的地址空间区域,调拨物理存储器后所有映射了同一个文件映射对象的的视图的其他进程就可以成功的访问已调拨的页面。

PS:稀疏调拨的内存映射文件尚未实例验证过,诸君谨慎参考。

【WIN32进阶之路】:内存映射文件的更多相关文章

  1. 内存映射文件详解-----C++实现

    先不说内存映射文件是什么.贴个代码先,. #include <iostream> #include <fcntl.h> #include <io.h> #inclu ...

  2. MemoryMappedFile 内存映射文件 msdn

    http://msdn.microsoft.com/zh-cn/library/dd997372%28v=vs.110%29.aspx 内存映射文件 .NET Framework 4.5 其他版本 1 ...

  3. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转

    原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing ...

  4. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped

    节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作 ...

  5. .NET 4.0中使用内存映射文件实现进程通讯

    操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段.Win32 API中也包含有创建内存映射文件的函数,然而,这些函数都 ...

  6. C++中使用内存映射文件处理大文件

    引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...

  7. JAVA NIO之浅谈内存映射文件原理与DirectMemory

    JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...

  8. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案

    C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...

  9. 【VS开发】内存映射文件3

    内存映射文件 内存映射文件,是由一个文件到一块内存的映射.Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping).内存映射文件与虚拟内存有些类似,通过内存映射文 ...

随机推荐

  1. 211. Add and Search Word - Data structure design

    题目: Design a data structure that supports the following two operations: void addWord(word) bool sear ...

  2. Oracle Exception 处理

    1.问题来源Oracle中可以用dbms_output.put_line来打印提示信息,但是很容易缓冲区就溢出了.可以用DBMS_OUTPUT.ENABLE(1000000);来设置缓冲区的大小.但是 ...

  3. python学习笔记一--字符串

    一.字符串: (一)字符串里单个元素的操作 1. 单个字符(元素)的序列组合. 2. 序列:单个字符的位置 3. 序列的操作:内置函数len获取长度,加位置索引 4. 获取字符串的里的元素:正向索引+ ...

  4. 查看32bit的ARM(比如ARMv7)反汇编

    1.使用./arm-eabi-as test.S -o test.o编译 2.使用./arm-eabi-objdump -d test.o反汇编

  5. flask开发遇到Internal Server Error的解决办法

    flask开发过程中遇到了Internal Server Error错误,可以在代码加上debug app.debug=True 这样就能看到错误信息了

  6. IOS,Object C学习过程中遇到的attributes

    @property 定义一个属性 @synthesize 告诉编译器自动为属性自动生成 getter 和setter方法 在定义属性的时候会用到如下@attributes nonatomic,告诉编译 ...

  7. poj 3253 Fence Repair (哈夫曼树 优先队列)

    题目:http://poj.org/problem?id=3253 没用long long wrong 了一次 #include <iostream> #include<cstdio ...

  8. C#中的预处理器指令

    C#中有许多名为“预处理器指令”的命令.这些命令从来不会转化为可执行代码中的命令,但会影响编译过程的各个方面. 例如,使用预处理器指令可以禁止编译器编译代码的某一部分.如果计划发布两个版本的代码,即基 ...

  9. JAX-RS入门 二 :运行

    上一节,已经成功的定义了一个REST服务,并且提供了具体的实现,不过我们还需要把它运行起来. 在上一节的装备部分,列举了必须的jar(在tomcat中运行)和可选的jar(作为一个独立的应用程序运行) ...

  10. light工具

    环境变量 C:\Users\zhangqm\AppData\Roaming\npm\; 安装 npm install -gd jresplus 不要用npm install -gd light pro ...