C#内存映射文件学习[转]
内存映射文件是由一个文件到进程地址空间的映射。
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#内存映射文件学习[转]的更多相关文章
- C#内存映射文件消息队列实战演练(MMF—MQ)
一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和 ...
- Linux下内存映射文件的用法简介
由于项目需要,所以学习了一下Linux下内存映射文件的用法,在这里共享一下自己的收获,希望大家提出宝贵意见,进行交流. 简介: 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区 ...
- C++中使用内存映射文件处理大文件
引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile() ...
- 《windows核心编程系列》十六谈谈内存映射文件
内存映射文件允许开发人员预订一块地址空间并为该区域调拨物理存储器,与虚拟内存不同的是,内存映射文件的物理存储器来自磁盘中的文件,而非系统的页交换文件.将文件映射到内存中后,我们就可以在内存中操作他们了 ...
- 内存映射文件MemoryMappedFile使用
参考资料: http://blog.csdn.net/bitfan/article/details/4438458 所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特 ...
- 使用ZwMapViewOfSection创建内存映射文件总结
标 题: [原创]使用ZwMapViewOfSection创建内存映射文件总结 作 者: 小覃 时 间: 2012-06-15,02:28:36 链 接: http://bbs.pediy.com/s ...
- 第17章 内存映射文件(3)_稀疏文件(Sparse File)
17.8 稀疏调拨的内存映射文件 17.8.1 稀疏文件简介 (1)稀疏文件(Sparse File):指的是文件中出现大量的0数据,这些数据对我们用处不大,但是却一样的占用空间.NTFS文件系统对此 ...
- 《Java核心技术卷二》笔记(二)文件操作和内存映射文件
文件操作 上一篇已经总结了流操作,其中也包括文件的读写.文件系统除了读写以为还有很多其他的操作,如复制.移动.删除.目录浏览.属性读写等.在Java7之前,一直使用File类用于文件的操作.Java7 ...
- 内存映射文件详解-----C++实现
先不说内存映射文件是什么.贴个代码先,. #include <iostream> #include <fcntl.h> #include <io.h> #inclu ...
随机推荐
- php monolog 的写日志到unix domain socket 测试终于成功
在另外一个客户端执行 php s.php后, 通过nc -lU /tmp/tg.sck 建立的unix domain socket 有接收到消息. <?php require 'vendor/a ...
- Java知识图谱
1.Java学习路径1 我想很多人看到这个路径可能会问我在哪里可以学习,所以就先附上这条路径的学习地址吧,这也是这张图片的来源,愿意学习的可以去看看:Java研发工程师学习路径 2.Java学习路径2 ...
- Hadoop架构设计、执行原理具体解释
1.Map-Reduce的逻辑过程 如果我们须要处理一批有关天气的数据.其格式例如以下: 依照ASCII码存储.每行一条记录 每一行字符从0開始计数,第15个到第18个字符为年 第25个到第29个字符 ...
- linux下weblogic11g成功安装后,启动报错Getting boot identity from user
<2015-7-1 下午05时46分33秒 CST> <Info> <Management> <BEA-141107> <Version: Web ...
- mac for smartSVN9 (8,9)破解方法 附smartSvn_keygen工具图文
mac for smartSVN9 (8,9)破解方法 附smartSvn_keygen工具 工具文件下载: http://files.cnblogs.com/files/xueshanshan/s ...
- 解决input,number类型的maxlength无效
使用input数字number类型的时候maxlength无效,假设需要控制输入数量为5,可以用以下方式: 无效: <input type="text" maxlength ...
- Struts 1 Struts 2
Key Technologies Primer https://struts.apache.org/primer.html Threads With Struts 1 you were require ...
- 滚动条样式优化(CSS3自定义滚动条样式 -webkit-scrollbar)
有时候觉得浏览器自带的原始滚动条不是很美观,那webkit浏览器是如何自定义滚动条的呢? Webkit支持拥有overflow属性的区域,列表框,下拉菜单,textarea的滚动条自定义样式.当然,兼 ...
- 设计模式-(6)适配器 (swift版)
用来解决接口适配问题的三种模式:适配器模式,桥接模式,外观模式. 一,概念 适配器模式,将一个类的结构转换成用户希望的另一个接口,使得原本接口不兼容的类能在一起工作.换句话说,适配器模式就是链接两种不 ...
- RK3288以太网的mac地址调试笔记【学习笔记】【原创】
平台信息:内核:linux3.1.0系统:android/android6.0平台:RK3288 作者:庄泽彬(欢迎转载,请注明作者) 邮箱:2760715357@qq.com 说明:提供以太网mac ...