博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在Linux和Windows平台上操作MemoryMappedFile(简称MMF)
阅读量:6250 次
发布时间:2019-06-22

本文共 7736 字,大约阅读时间需要 25 分钟。

操作系统很早就开始使用内存映射文件(Memory Mapped File)来作为进程间的共享存储区,这是一种非常高效的进程通讯手段。.NET 4.0新增加了一个System.IO. MemoryMappedFiles命名空间,其中添加了几个类和相应的枚举类型,从而使我们可以很方便地创建内存映射文件。Mono 3.2也有这个类来操作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
(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
(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)
相关文章:
 
 
 
 
 
 
 

转载地址:http://krusa.baihongyu.com/

你可能感兴趣的文章
2017.12.25
查看>>
react--1.创建项目
查看>>
11月20日学习内容整理:jquery插件
查看>>
预科班第四次考核总结
查看>>
html
查看>>
数据分析师到底在做什么?
查看>>
pt-heartbeat工具监控MySQL复制延迟
查看>>
指尖下的js —— 多触式web前端开发之三:处理复杂手势(转)
查看>>
spring boot项目配置文件集合
查看>>
cube-ui的用法
查看>>
2015.4.21 SetWindowPos函数用法
查看>>
2011-12-14 调用cmd并获得输入输出+网络访问
查看>>
TCP定时器详解
查看>>
if判断,switch语句
查看>>
Arduino入门之前
查看>>
zoj 1904 Beavergnaw 计算圆柱和圆台的体积
查看>>
整理了一份招PHP高级工程师的面试题(转)
查看>>
学习Raft算法的笔记
查看>>
第十一周编程总结
查看>>
darknet源码学习
查看>>