在Linux和Windows平台上操作MemoryMappedFile(简称MMF)
操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段。.NET 4.0新增加了一个System.IO. MemoryMappedFiles命名空间,其中添加了几个类和相应的枚举类型,从而使我们可以很方便地创建内存映射文件。Mono 3.2也有这个类来操作Linux下的内存映射文件,《MemoryMappedFile 在 Mono in Linux 的开发笔记》详细的介绍了Mono和.NET 4的实现区别,为了让代码能够在Linux和Windows平台都正常运行,建议统一使用
MemoryMappedFile.CreateFromFile(
FileStream fileStream,
String mapName,
Int64 capacity,
MemoryMappedFileAccess access,
System.IO.MemoryMappedFiles.MemoryMappedFileSecurity memoryMappedFileSecurity,
HandleInheritability inheritability,
Boolean leaveOpen)
方法来创建MMF,并且在调用前确保指定的文件流大小与capacity参数值相同。
下面我给出在Windows和Linux下都运行正常的代码:
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections.Generic;
using System.Text;
using System.Security.AccessControl;
using System.Configuration; namespace ManagedMMF
{
class Program
{
static void Main(string[] args)
{
// Build a sample object and report records
HikingDatabase hikingData = BuildDatabase(5000, 50);
Console.WriteLine("Dummy database object created with " + hikingData.hikes.Length + " records.");
string mmfile = ConfigurationManager.AppSettings["mmf"];
// Write object to MMF
WriteObjectToMMF(mmfile, hikingData); // Clear object and report
hikingData = null;
Console.WriteLine("Database object has been destroyed."); // Read new object from MMF and report records
hikingData = ReadObjectFromMMF(mmfile) as HikingDatabase;
Console.WriteLine("Dummy database object re-loaded from MMF with " + hikingData.hikes.Length + " records."); // Wait for input and terminate
Console.ReadLine();
} #region Generic MMF read/write object functions static void WriteObjectToMMF(string mmfFile, object objectData)
{
string mapName = "MyFile";
if (IsMono())
{
mapName = mmfFile;
}
// Convert .NET object to byte array
byte[] buffer = ObjectToByteArray(objectData);
using (FileStream fs = new FileStream(mmfFile, FileMode.Create, FileAccess.ReadWrite))
{
fs.SetLength(buffer.Length);
// Create a new memory mapped file
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fs, mapName, buffer.Length,
MemoryMappedFileAccess.ReadWrite, new MemoryMappedFileSecurity() { }, HandleInheritability.Inheritable, true))
{
// Create a view accessor into the file to accommmodate binary data size
using (MemoryMappedViewAccessor mmfWriter = mmf.CreateViewAccessor(0, buffer.Length))
{
// Write the data
mmfWriter.WriteArray<byte>(0, buffer, 0, buffer.Length);
}
}
}
} static object ReadObjectFromMMF(string mmfFile)
{
string mapName = "MyFile";
if (IsMono())
{
mapName = mmfFile;
}
using (FileStream fs = new FileStream(mmfFile, FileMode.Open, FileAccess.ReadWrite))
{
// Get a handle to an existing memory mapped file
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fs, mapName, fs.Length,
MemoryMappedFileAccess.ReadWrite, new MemoryMappedFileSecurity() { }, HandleInheritability.Inheritable, true))
{
// Create a view accessor from which to read the data
using (MemoryMappedViewAccessor mmfReader = mmf.CreateViewAccessor())
{
// Create a data buffer and read entire MMF view into buffer
byte[] buffer = new byte[mmfReader.Capacity];
mmfReader.ReadArray<byte>(0, buffer, 0, buffer.Length); // Convert the buffer to a .NET object
return ByteArrayToObject(buffer);
}
}
}
} static bool IsMono()
{
Type t = Type.GetType("Mono.Runtime");
return t != null;
} #endregion #region Object/Binary serialization static object ByteArrayToObject(byte[] buffer)
{
BinaryFormatter binaryFormatter = new BinaryFormatter(); // Create new BinaryFormatter
MemoryStream memoryStream = new MemoryStream(buffer); // Convert byte array to memory stream, set position to start
return binaryFormatter.Deserialize(memoryStream); // Deserializes memory stream into an object and return
} static byte[] ObjectToByteArray(object inputObject)
{
BinaryFormatter binaryFormatter = new BinaryFormatter(); // Create new BinaryFormatter
MemoryStream memoryStream = new MemoryStream(); // Create target memory stream
binaryFormatter.Serialize(memoryStream, inputObject); // Convert object to memory stream
return memoryStream.ToArray(); // Return memory stream as byte array
} #endregion static HikingDatabase BuildDatabase(int recordCount, int gpsCoordCount)
{
Random rand = new Random(); HikingDatabase hikingData = new HikingDatabase();
hikingData.Description = "My hikes, 2010 to 2012";
hikingData.hikes = new Hike[recordCount];
for (int i = 0; i < hikingData.hikes.Length; i++)
{
hikingData.hikes[i] = new Hike();
hikingData.hikes[i].Description = "This is a description of this particular record. ";
hikingData.hikes[i].Date = DateTime.Now.ToLongDateString();
hikingData.hikes[i].GPSTrack = new Coord[gpsCoordCount];
for (int j = 0; j < hikingData.hikes[i].GPSTrack.Length; j++)
{
hikingData.hikes[i].GPSTrack[j] = new Coord();
hikingData.hikes[i].GPSTrack[j].x = rand.NextDouble() * 1000000;
hikingData.hikes[i].GPSTrack[j].y = rand.NextDouble() * 1000000;
hikingData.hikes[i].GPSTrack[j].z = rand.NextDouble() * 1000;
}
}
return hikingData;
}
} #region Sample object for I/O [Serializable]
public class HikingDatabase
{
public string Description;
public Hike[] hikes;
} [Serializable]
public class Hike
{
public string Description;
public string Date;
public Coord[] GPSTrack;
} [Serializable]
public class Coord
{
public double x;
public double y;
public double z;
}
#endregion
}
所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特定的文件相对应。进程将这块内存区域映射到自己的地址空间中,访问它就象是访问普通的内存一样。
在.NET中,使用MemoryMappedFile对象表示一个内存映射文件,通过它的CreateFromFile()方法根据磁盘现有文件创建内存映射文件,调用这一方法需要提供一个与磁盘现有文件相对应的FileStream对象。
当MemoryMappedFile对象创建之后,我们并不能直接对其进行读写,必须通过一个MemoryMappedViewAccessor对象来访问这个内存映射文件。MemoryMappedFile. CreateViewAccessor()方法可以创建MemoryMappedViewAccessor对象,而此对象提供了一系列读写的方法,用于向内存映射文件中读取和写入数据。
在创建内存映射文件访问对象需要指定它所能访问的内存映射文件的内容范围,这个“范围”称为“内存映射视图(Memory Mapped View)”。可以将它与“放大镜”类比,当使用一个放大镜阅读书籍时,一次只能放大指定部分的文字。类似地,我们只能在内存映射视图所规定的范围内存取内存映射文件。
如果要向内存映射文件中序列化对象,必须将内存映射文件转换为可顺序读取的流。幸运的是,MemoryMappedFile类的CreateViewStream()方法可以创建一个MemoryMappedViewStream对象,通过它即可序列化对象。这个对象允许序列访问映射视图;这个可能是使用映射视图流(mapped view streams)与使用允许随即访问的accessor对象相比的最大缺点。 A quick (low-latency) IPC channel for .NET (Using MemoryMappedFile and Event)
https://github.com/geffzhang/QuickIPC
相关文章:
Memory Mapped File Interoperability with .NET Objects
Programming Memory-Mapped Files with the .NET Framework
.Net Framework 4.0開始有包好的MemoryMappedFile的類別了
Working with memory mapped files in .NET 4
MemoryMappedFile 在 Mono in Linux 的开发笔记
MemoryMappedFile使用小结
System.IO之内存映射文件共享内存 https://github.com/geffzhang/QuickIPC
在Linux和Windows平台上操作MemoryMappedFile(简称MMF)的更多相关文章
- 如何在微软Windows平台上打造出你的Linux开发环境(转载)
如何在微软Windows平台上打造出你的Linux开发环境 投递人 itwriter 发布于 2013-12-10 11:18 评论(1) 有348人阅读 原文链接 [收藏] « » 英文原文: ...
- 在Windows平台上安装Node.js及NPM模块管理
1. 下载Node.js官方Windows版程序:http://nodejs.org/#download 从0.6.1开始,Node.js在Windows平台上提供了两种安装方式,一是.MSI安 ...
- cygwin -- 在windows平台上运行的unix模拟环境
cygwin是一个在windows平台上运行的unix模拟环境,是cygnus solutions公司开发的自由软件(该公司开发了很多好东西,著名的还有eCos,不过现已被Redhat收购).它对于学 ...
- 分享一些 Windows 平台上的神器
下面分享一些 Windows 平台上日常开发使用的软件,有些软件我自认为是神器,可以大大提高效率. 编辑器类软件 IntelliJ IDEA IntelliJ IDEA 内部集成 Java 开发环境, ...
- MySQL 在Windows平台上的安装及实例多开
MySQL在Windows平台上的安装及实例多开 by:授客 QQ:1033553122 测试环境 Win7 64 mysql-5.7.20-winx64.zip 下载地址: https://cd ...
- 在Linux和Windows系统上安装Nginx服务器的教程
在Linux和Windows系统上安装Nginx服务器的教程 1.在CentOS系统上安装Nginx 在 CentOS6 版本的 EPEL 源中,已经加入了 nginx 的 rpm 包,不过此 RP ...
- (转)在Windows平台上安装Node.js及NPM模块管理
本文转载自:http://www.cnblogs.com/seanlv/archive/2011/11/22/2258716.html 之前9月份的时候我写了一篇关于如何在Windows平台上手工管理 ...
- Windbg是windows平台上强大的调试器
基础调试命令 - .dump/.dumpcap/.writemem/!runaway Windbg是windows平台上强大的调试器,它相对于其他常见的IDE集成的调试器有几个重要的优势, Windb ...
- 国密SM3算法在linux和windows平台结果不一致问题
什么是sm3,是一种类似于sha256的哈希算法,是咱们国家的哈希标准算法: 最近在使用sm3算法时,同样的一份数据,调用同样的sm3接口,发现得到的结果是不一样的: 那么在应用过的过程中,如果同样的 ...
随机推荐
- Shell特殊变量
$ 表示当前Shell进程的ID,即pid $echo $$ 运行结果 特殊变量列表 变量 含义 $0 当前脚本的文件名 $n 传递给脚本或函数的参数.n 是一个数字,表示第几个参数.例如,第一个参数 ...
- python开发编译器
引言 最近刚刚用python写完了一个解析protobuf文件的简单编译器,深感ply实现词法分析和语法分析的简洁方便.乘着余热未过,头脑清醒,记下一点总结和心得,方便各位pythoner参考使用. ...
- 用CIL写程序:你好,沃尔德
前言: 项目紧赶慢赶总算在年前有了一些成绩,所以沉寂了几周之后,小匹夫也终于有时间写点东西了.以前匹夫写过一篇文章,对CIL做了一个简单地介绍,不过不知道各位看官看的是否过瘾,至少小匹夫觉得很不过瘾. ...
- 02.LoT.UI 前后台通用框架分解系列之——灵活的菜单栏
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 前端学HTTP之报文首部
前面的话 首部和方法配合工作,共同决定了客户端和服务器能做什么事情.在请求和响应报文中都可以用首部来提供信息,有些首部是某种报文专用的,有些首部则更通用一些.本文将详细介绍HTTP报文中的首部 结构 ...
- 开源免费且稳定实用的.NET PDF打印组件itextSharp(.NET组件介绍之八)
在这个.NET组件的介绍系列中,受到了很多园友的支持,一些园友(如:数据之巅. [秦时明月]等等这些大神 )也给我提出了对应的建议,我正在努力去改正,有不足之处还望大家多多包涵.在传播一些简单的知识的 ...
- AFNetworking报错"_UTTypeCopyPreferredTagWithClass", referenced from: _AFContentTypeForPathExtens
问题: 在和Unity交互的过程中,从Unity开发工具打包出来的项目文件,在添加AFNetworking库,运行时报出以下错误: Undefined symbols for architecture ...
- Android中Activity处理返回结果的实现方式
大家在网上购物时都有这样一个体验,在确认订单选择收货人以及地址时,会跳转页面到我们存入网站内的所有收货信息(包含收货地址,收货人)的界面供我们选择,一旦我们点击其中某一条信息,则会自动跳转到订单提交界 ...
- 如何通过Git GUI将自己本地的项目上传至Github
最近在学习node.js和react,顺便复习了下AngluarJS相关的东西,写了些小demo想放在GitHub上,之前仅限于只申请了GitHub账号从没用过,今天花半天时间查资料认真学习Githu ...