原文链接

内存映射文件是由一个文件到进程地址空间的映射。

C#提供了允许应用程序把文件映射到一个进程的函(MemoryMappedFile.CreateOrOpen)。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。

共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件。共享内存的主语是进程(Process),操作系统默认会给每一个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程的。而有时候需要在不同进程之间访问同一段内存,怎么办呢?操作系统给出了创建访问共享内存的API,需要共享内存的进程可以通过这一组定义好的API来访问多个进程之间共有的内存,各个进程访问这一段内存就像访问一个硬盘上的文件一样。而.Net 4.0中引入了System.IO.MemoryMappedFiles命名空间,这个命名空间的类对windows 共享内存相关API做了封装,使.Net程序员可以更方便的使用内存映射文件。

内存映射文件实现进程间通讯

内存映射文件是实现进程通讯的又一种方法,我们可以通过共享剪贴板、共享物理文件来实现进程间的数据共享,这里我们还可以通过内存映射文件来实现共享,这样,文件内的数据就可以用内存读/写指令来访问,而不是用ReadFile和WriteFile这样的I/O系统函数,从而提高了文件存取速度。这种方式更加快捷高效,最适用于需要读取文件并且对文件内包含的信息做语法分析的应用程序,如:对输入文件进行语法分析的彩色语法编辑器,编译器等。这种数据共享是让两个或多个进程映射同一文件映射对象的视图,即它们在共享同一物理存储页。这样,当一个进程向内存映射文件的一个视图写入数据时,其他的进程立即在自己的视图中看到变化。

注意:

对文件映射对象要使用同一名字。

是让两个或多个进程映射同一文件映射对象的视图,即它们在共享同一物理存储页。这样,当一个进程向内存映射文件的一个视图写入数据时,其他的进程立即在自己的视图中看到变化。但要注意,对文件映射对象要使用同一名字。

内存映射文件使用实例:

1.      在同一进程内同时读写同一内存映射文件

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.MemoryMappedFiles; namespace UseMMFInProcess
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
CreateMemoryMapFile();
}
private const int FILE_SIZE = ;
/// <summary>
/// 引用内存映射文件
/// </summary>
private MemoryMappedFile memoryFile = null;
/// <summary>
/// 用于访问内存映射文件的存取对象
/// </summary>
private MemoryMappedViewAccessor accessor1, accessor2,accessor;
/// <summary>
/// 创建内存映射文件
/// </summary>
private void CreateMemoryMapFile()
{
try
{
memoryFile = MemoryMappedFile.CreateFromFile("MyFile.dat", FileMode.OpenOrCreate, "MyFile", FILE_SIZE);
//访问文件前半段
accessor1 = memoryFile.CreateViewAccessor(, FILE_SIZE / );
//访问文件后半段
accessor2 = memoryFile.CreateViewAccessor(FILE_SIZE / , FILE_SIZE / );
//访问全部文件
accessor = memoryFile.CreateViewAccessor();
//InitFileContent();
lblInfo.Text = "内存文件创建成功";
ShowFileContents();
}
catch (Exception ex)
{
lblInfo.Text = ex.Message;
}
}
/// <summary>
/// 关闭并释放资源
/// </summary>
private void DisposeMemoryMapFile()
{
if (accessor1 != null)
accessor1.Dispose();
if (accessor2 != null)
accessor2.Dispose();
if (memoryFile != null)
memoryFile.Dispose();
} private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
DisposeMemoryMapFile();
} private void btnWrite1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length == )
{
lblInfo.Text = "请输入一个字符";
return;
}
char[] chs = textBox1.Text.ToCharArray();
char ch = chs[]; for (int i = ; i < FILE_SIZE / ; i += )
accessor1.Write(i, ch); lblInfo.Text = "字符“" + ch + "”已写到文件前半部份";
ShowFileContents();
} private void btnShow_Click(object sender, EventArgs e)
{
ShowFileContents();
} /// <summary>
/// 初始化文件内容为可视的字符“0”
/// </summary>
private void InitFileContent()
{
for (int i = ; i < FILE_SIZE; i += )
accessor.Write(i,'');
}
/// <summary>
/// 显示文件内容
/// </summary>
private void ShowFileContents()
{
StringBuilder sb = new StringBuilder(FILE_SIZE);
sb.Append("上半段内容:\n"); int j = ;
for (int i = ; i < FILE_SIZE / ; i += )
{
sb.Append("\t");
char ch = accessor.ReadChar(i);
sb.Append(j);
sb.Append(":");
sb.Append(ch);
j++;
}
sb.Append("\n下半段内容:\n"); for (int i = FILE_SIZE / ; i < FILE_SIZE; i += )
{
sb.Append("\t");
char ch = accessor.ReadChar(i);
sb.Append(j);
sb.Append(":");
sb.Append(ch);
j++;
}
richTextBox1.Text = sb.ToString();
} private void btnWrite2_Click(object sender, EventArgs e)
{
if (textBox2.Text.Length == )
{
lblInfo.Text = "请输入一个字符";
return;
}
char[] chs = textBox2.Text.ToCharArray();
char ch = chs[]; for (int i = ; i < FILE_SIZE / ; i += )
accessor2.Write(i, ch);
lblInfo.Text = "字符“" + ch + "”已写到文件后半部份";
ShowFileContents();
}
}
}

2.      使用内存映射文件在进程间传送值类型数据

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace UseMMFBetweenProcess
{
/// <summary>
/// 要共享的数据结构,注意,其成员不能是引用类型
/// </summary>
public struct MyStructure
{
public int IntValue
{
get;
set;
}
public float FloatValue
{
get;
set;
}
}
} using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.MemoryMappedFiles;
using System.IO; namespace UseMMFBetweenProcess
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
InitMemoryMappedFile();
} /// <summary>
/// 内存映射文件的容量
/// </summary>
private const int FileSize = * ;
private MemoryMappedFile file = null;
private MemoryMappedViewAccessor accessor = null; /// <summary>
/// 初始化内存映射文件
/// </summary>
private void InitMemoryMappedFile()
{
file = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess", FileSize);
accessor = file.CreateViewAccessor();
lblInfo.Text = "内存文件创建或连接成功";
} /// <summary>
/// 要共享的数据对象
/// </summary>
private MyStructure data; /// <summary>
/// 显示数据到窗体上
/// </summary>
private void ShowData()
{
textBox1.Text = data.IntValue.ToString();
textBox2.Text = data.FloatValue.ToString();
} /// <summary>
/// 根据用户输入更新数据
/// </summary>
private void UpdateData()
{
data.IntValue = int.Parse(textBox1.Text);
data.FloatValue = float.Parse(textBox2.Text);
} private void btnSave_Click(object sender, EventArgs e)
{
try
{
UpdateData();
accessor.Write<MyStructure>(, ref data);
lblInfo.Text = "数据已经保存到内存文件中";
}
catch (Exception ex)
{
lblInfo.Text = ex.Message;
}
} private void btnLoad_Click(object sender, EventArgs e)
{
accessor.Read<MyStructure>(, out data);
ShowData();
lblInfo.Text = "成功从内存文件中提取了数据";
} private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (accessor != null)
accessor.Dispose();
if (file != null)
file.Dispose();
}
}
}

3.      利用序列化技术通过内存映射文件实现进程通讯

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary; namespace UseMMFBetweenProcess2
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
InitMemoryMappedFile();
} /// <summary>
/// 图片
/// </summary>
private Image bmp
{
get
{
return pictureBox1.Image;
}
set
{
pictureBox1.Image = value;
}
} /// <summary>
/// 图片说明
/// </summary>
private string info
{
get
{
return txtImageInfo.Text;
}
set
{
txtImageInfo.Text = value;
}
} private MemoryMappedFile memoryFile = null; private MemoryMappedViewStream stream = null; /// <summary>
/// 最大容量:10M
/// </summary>
private const int FileSize = * * ; /// <summary>
/// 创建内存映射文件,获取其读写流
/// </summary>
private void InitMemoryMappedFile()
{
try
{
memoryFile = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess2", FileSize);
stream = memoryFile.CreateViewStream();
}
catch (Exception ex )
{
MessageBox.Show(ex.Message);
Close();
}
}
/// <summary>
/// 释放相关资源
/// </summary>
private void DisposeMemoryMappedFile()
{
if (stream != null)
stream.Close();
if (memoryFile != null)
memoryFile.Dispose();
} private void btnLoadPic_Click(object sender, EventArgs e)
{
ChooseImageFile();
} //选择图片
private void ChooseImageFile()
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
bmp = new Bitmap(openFileDialog1.FileName);
}
}
//根据用户设定的信息创建对象
private MyPic CreateMyPicObj()
{
MyPic obj = new MyPic();
obj.pic = bmp;
obj.picInfo = info;
return obj;
} /// <summary>
/// 将MyPic对象保存到内存映射文件中
/// </summary>
private void SaveToMMF()
{
try
{
MyPic obj = CreateMyPicObj();
IFormatter formatter = new BinaryFormatter();
stream.Seek(, SeekOrigin.Begin);
formatter.Serialize(stream, obj);
MessageBox.Show("对象已保存到内存映射文件中");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} private void LoadFromMMF()
{
try
{
// CreateMyPicObj();
IFormatter formatter = new BinaryFormatter();
stream.Seek(, SeekOrigin.Begin);
MyPic obj = formatter.Deserialize(stream) as MyPic;
if (obj != null)
{
bmp = obj.pic;
info = obj.picInfo;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
} private void btnExit_Click(object sender, EventArgs e)
{
Close();
} private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
DisposeMemoryMappedFile();
} private void btnSaveToMMF_Click(object sender, EventArgs e)
{
SaveToMMF();
} private void btnLoadFromMMF_Click(object sender, EventArgs e)
{
LoadFromMMF();
}
}
}

C#内存映射文件学习[转]的更多相关文章

  1. C#内存映射文件消息队列实战演练(MMF—MQ)

    一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和 ...

  2. Linux下内存映射文件的用法简介

    由于项目需要,所以学习了一下Linux下内存映射文件的用法,在这里共享一下自己的收获,希望大家提出宝贵意见,进行交流. 简介: 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区 ...

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

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

  4. 《windows核心编程系列》十六谈谈内存映射文件

    内存映射文件允许开发人员预订一块地址空间并为该区域调拨物理存储器,与虚拟内存不同的是,内存映射文件的物理存储器来自磁盘中的文件,而非系统的页交换文件.将文件映射到内存中后,我们就可以在内存中操作他们了 ...

  5. 内存映射文件MemoryMappedFile使用

    参考资料: http://blog.csdn.net/bitfan/article/details/4438458 所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特 ...

  6. 使用ZwMapViewOfSection创建内存映射文件总结

    标 题: [原创]使用ZwMapViewOfSection创建内存映射文件总结 作 者: 小覃 时 间: 2012-06-15,02:28:36 链 接: http://bbs.pediy.com/s ...

  7. 第17章 内存映射文件(3)_稀疏文件(Sparse File)

    17.8 稀疏调拨的内存映射文件 17.8.1 稀疏文件简介 (1)稀疏文件(Sparse File):指的是文件中出现大量的0数据,这些数据对我们用处不大,但是却一样的占用空间.NTFS文件系统对此 ...

  8. 《Java核心技术卷二》笔记(二)文件操作和内存映射文件

    文件操作 上一篇已经总结了流操作,其中也包括文件的读写.文件系统除了读写以为还有很多其他的操作,如复制.移动.删除.目录浏览.属性读写等.在Java7之前,一直使用File类用于文件的操作.Java7 ...

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

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

随机推荐

  1. VB6 如何连接MYSQL数据库

    1 从官网下载MYSQL的ODBC,选择与自己操作系统对应的版本(前提是你安装了MYSQL) http://dev.mysql.com/downloads/connector/odbc/   2 安装 ...

  2. 安装和配置Apache-tomcat

    https://tomcat.apache.org/download-90.cgi 我随便下载了一个,而且解压了 我把路径:G:\php\apache-tomcat-9.0.6\bin 放入path, ...

  3. Deepin-快捷方式设置

    Linux无非就是命令命令命令,而不是点点点,下面介绍快捷方式 然后点击 最后找到快捷方式(鼠标滚轮下滑) 快捷方式自个看着修改

  4. Windows 上通过本地搭建 Jekyll环境

    一 准备Ruby环境 1 我们首先须要安装Ruby.从站点下载Ruby 上下载Ruby最新版和对应的DevKit. 我下载的是Ruby 2.1.4 (x64)和DevKit-mingw64-6 .注意 ...

  5. Web安全漏洞及攻击

    背景介绍 先说一个在互联网上常见,但是普通人又不太理解的东西--“验证码”. 验证码(CAPTCHA)是“Completely Automated Public Turing test to tell ...

  6. 如何将Python的py程序打包成跨平台的exe文件

    在编写了自己的第一个可以爬写网页源代码的程序之后,发现如果在没有安装了pythonLDLE程序的计算机上根本就跑不出来.所以开始寻找可以将程序打包成跨平台运行的exe文件. 经过自己费力的谷歌没有一个 ...

  7. 1.NetDh框架之数据库操作层--Dapper简单封装,可支持多库实例、多种数据库类型等(附源码和示例代码)

    1.NetDh框架开始的需求场景 需求场景: 1.之前公司有不同.net项目组,有的项目是用SqlServer做数据库,有的项目是用Oracle,后面也有可能会用到Mysql等,而且要考虑后续扩展成主 ...

  8. 网易新闻client(高仿)

    近期整理了下自己曾经做过的项目,决定分享出来.本篇所展示的是仿网易新闻client,服务端是在新浪SAE部署着的.所以大家下载后,可直接在手机上看到效果.接下来看效果图: watermark/2/te ...

  9. TF-IDF与余弦类似性的应用(一):自己主动提取关键词

    作者: 阮一峰 日期: 2013年3月15日 原文链接:http://www.ruanyifeng.com/blog/2013/03/tf-idf.html 这个标题看上去好像非常复杂,事实上我要谈的 ...

  10. struts2的一些小问题

    1.action和ValueStack的关系2.ValueStack的类set()方法和setValue()方法的区别3.ValueStack的类push()方法的作用4.从ValueStack对象中 ...