第一章:源起 

遇到一个问题,如果一个客户数据文件有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. 186. Reverse Words in a String II

    题目: Given an input string, reverse the string word by word. A word is defined as a sequence of non-s ...

  2. python学习笔记三--字典的使用

    一.基本使用: 1. 赋值:{key:value} 1.1 与列表相同处:会改变索引(键)相关联的值的改变 1.2 与列表不同处:不用考虑值的长度,而列表是有序的需要考虑末尾偏移量,超过末尾偏移量的会 ...

  3. [原]Unity3D深入浅出 - 脚本开发基础(Scripts)

    常用脚本事件: Update:每帧调用一次 Start:在第一次Update执行前调用 Awake:脚本实例在创建时调用 FixedUpdate:每个固定物理时间间隔调用一次 LateUpdate:每 ...

  4. python扩展实现方法--python与c混和编程

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...

  5. 【转】Java 截取字符串

    原文网址:http://blog.csdn.net/yelangjueqi/article/details/9149699 截取字符串常用方法: 1.length() 字符串的长度 例:char ch ...

  6. android利用WebView实现浏览器的封装

    android提供了封装浏览器的接口,可以让开发者利用自己的view显示网页内容.今天又实现研究了一下,利用WebView显示浏览器内容,还可以利用 WebViewClient显示自己需要的内容. 参 ...

  7. C# 随机读写入文件

    先来代码再解释 public Worker(string path) { FileStream fs = new FileStream( path, FileMode.OpenOrCreate, Fi ...

  8. mina2

      远程通信 Mina2 学习笔记 作者:李少华 邮箱:xiaosanshaoli@126.com QQ:305409913 2010-12-23   初稿 引言... 1 一.       Mina ...

  9. HDU 4825-Xor Sum(trie)

    题意: 给你一组数,开始询问给一个数  求组中与该数异或值最大的数. 分析:根据异或的特点 要想得到的异或值最大 尽可能的让两个数的每位都相反 先把给定的一组数建树,数的最后一位对应的节点保存这个数的 ...

  10. as3+java+mysql(mybatis) 数据自动工具(六)

    这篇来写一些常量定义的实例.我一般在配置常量的时候,都会让 bitOffset = 20,这样是一个比较好的分配,就是每个分组可以有 0xFFFFF(1048575) 个常量,0xFFF(4095) ...