在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之内存映射文件共享内存
- JavaWeb12-JSP, EL表达式,JSTL标签
- JavaWeb11-jsp.cookie.session(1)
- 交互式使用 R题(shell)
- union(并),setdiff(差),intersect(交)R语言含义
- JavaWeb11-jsp.cookie.session(2)
- 一个慢查询报警的简单处理 (r8笔记第12天)
- 厚土Go学习笔记 | 38. goroutine轻量级线程
- 厚土Go学习笔记 | 36. web服务指定路径下的get参数接收与处理
- Java开发Spring笔记第二天
- PHP调用Go服务的正确方式 - Unix Domain Sockets
- 一条看似平常的报警邮件所做的分析(r8笔记第9天)
- 55. 上传文件(Web版) | 厚土Go学习笔记
- R语言与机器学习学习笔记(分类算法
- 54. 心跳的实现 | 厚土Go学习笔记
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言预测人口死亡率:用李·卡特模型、非线性模型进行平滑估计
- Dockerfile 指令
- Docker 构建容器Tomcat+Nginx+MySQL
- 三种动态控制SAP CRM WebClient UI assignment block显示与否的方法
- TCGA数据库中癌症名称缩写
- CloudFlare自定义节点优化网站
- 什么是SSL?为什么要为WordPress网站使用SSL?
- R语言再保险合同定价案例研究
- SAP CRM附件的技术属性设计原理
- R语言对混合分布中的不可观测与可观测异质性因子分析
- R替换函数gsub
- R语言泊松回归对保险定价建模中的应用:风险敞口作为可能的解释变量
- asp dotnet core 提供大文件下载的测试
- R语言模拟人类生活预期寿命动态可视化动画图gif
- Python遍历字典