操作系统很早就开始使用内存映射文件(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)的更多相关文章

  1. 如何在微软Windows平台上打造出你的Linux开发环境(转载)

    如何在微软Windows平台上打造出你的Linux开发环境 投递人 itwriter 发布于 2013-12-10 11:18 评论(1) 有348人阅读  原文链接  [收藏]  « » 英文原文: ...

  2. 在Windows平台上安装Node.js及NPM模块管理

    1. 下载Node.js官方Windows版程序:http://nodejs.org/#download    从0.6.1开始,Node.js在Windows平台上提供了两种安装方式,一是.MSI安 ...

  3. cygwin -- 在windows平台上运行的unix模拟环境

    cygwin是一个在windows平台上运行的unix模拟环境,是cygnus solutions公司开发的自由软件(该公司开发了很多好东西,著名的还有eCos,不过现已被Redhat收购).它对于学 ...

  4. 分享一些 Windows 平台上的神器

    下面分享一些 Windows 平台上日常开发使用的软件,有些软件我自认为是神器,可以大大提高效率. 编辑器类软件 IntelliJ IDEA IntelliJ IDEA 内部集成 Java 开发环境, ...

  5. MySQL 在Windows平台上的安装及实例多开

    MySQL在Windows平台上的安装及实例多开   by:授客 QQ:1033553122 测试环境 Win7 64 mysql-5.7.20-winx64.zip 下载地址: https://cd ...

  6. 在Linux和Windows系统上安装Nginx服务器的教程

    在Linux和Windows系统上安装Nginx服务器的教程  1.在CentOS系统上安装Nginx 在 CentOS6 版本的 EPEL 源中,已经加入了 nginx 的 rpm 包,不过此 RP ...

  7. (转)在Windows平台上安装Node.js及NPM模块管理

    本文转载自:http://www.cnblogs.com/seanlv/archive/2011/11/22/2258716.html 之前9月份的时候我写了一篇关于如何在Windows平台上手工管理 ...

  8. Windbg是windows平台上强大的调试器

    基础调试命令 - .dump/.dumpcap/.writemem/!runaway Windbg是windows平台上强大的调试器,它相对于其他常见的IDE集成的调试器有几个重要的优势, Windb ...

  9. 国密SM3算法在linux和windows平台结果不一致问题

    什么是sm3,是一种类似于sha256的哈希算法,是咱们国家的哈希标准算法: 最近在使用sm3算法时,同样的一份数据,调用同样的sm3接口,发现得到的结果是不一样的: 那么在应用过的过程中,如果同样的 ...

随机推荐

  1. JavaScript 对数据处理的5个API

    JavaScript对数据处理包括向上取整.向下取整.四舍五入.固定精度和固定长度5种方式,分别对应ceil,floor,round,toFixed,toPrecision等5个API,本文将对这5个 ...

  2. Entity Framework教程(第二版)

    源起 很多年前刚毕业那阵写过一篇关于Entity Framework的文章,没发首页却得到100+的推荐.可能是当时Entity Framework刚刚发布介绍EF的文章比较少.一晃这么多年过去了,E ...

  3. 阿里签名中URLEncode于C#URLEncod不同之处

    问题 如上图所示,阿里云的PercentEncode 转换! 为 %21 PercentEncode 源码为: package com.aliyuncs.auth; import java.io.Un ...

  4. Js 原型和原型链

    Js中通过原型和原型链实现了继承 Js对象属性的访问,首先会查找自身是否拥有这个属性 如果查到,则返回属性值,如果找不到,就会遍历原型链,一层一层的查找,如果找到就会返回属性值 直到遍历完Object ...

  5. ExtJS 4.2 业务开发(三)数据添加和修改

    接上面的船舶管理业务,这里介绍添加和修改操作. 目录 1. 添加操作 2. 修改操作 3. 在线演示 1. 添加操作 1.1 创建AddShipWindow.js 在业务中的view目录下创建一个Ad ...

  6. NET Core-学习笔记(四)

    经过前面分享的三篇netcore心得再加上本篇分享的知识,netcore大部分常用知识应该差不多了,接下来将不会按照章节整合一起分享,因为涉及到的东西整合到一起篇幅太大了,所以后面分享将会按照某一个知 ...

  7. iOS开发之多种Cell高度自适应实现方案的UI流畅度分析

    本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...

  8. H5程序员如何利用cordova开发跨平台应用

    什么是Cordova? Cordova以前也叫PhoneGap,它提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头.麦克风等.Cordova还 ...

  9. “fixed+relative==absolute”——对BFC的再次思考

    好久没写博客了,刚好今天跨年夜没约到什么妹子,在家宅着不如写点东西好了. 需求 昨天晚上,给公司年会做一个移动端的投票页面,遇到一个UI优化的问题: · 正文内容少于一屏时,投票提交按钮固定显示在页面 ...

  10. D3.js学习(六)

    上节我们学习了如何绘制多条曲线, 以及给不同的曲线指定不同的坐标系.在这节当中,我们会对坐标轴标签相关的处理进行学习.首先,我们来想一个问题, 如何我们的x轴上的各个标签的距离比较近,但是标签名又比较 ...