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 = 512;
        /// <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(0, FILE_SIZE / 2);
                //访问文件后半段
                accessor2 = memoryFile.CreateViewAccessor(FILE_SIZE / 2, FILE_SIZE / 2);
                //访问全部文件
                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 == 0)
            {
                lblInfo.Text = "请输入一个字符";
                return;
            }
            char[] chs = textBox1.Text.ToCharArray();
            char ch = chs[0];

            for (int i = 0; i < FILE_SIZE / 2; i += 2)
                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 = 0; i < FILE_SIZE; i += 2)
                accessor.Write(i,‘0‘);
        }
        /// <summary>
        /// 显示文件内容
        /// </summary>
        private void ShowFileContents()
        {
            StringBuilder sb = new StringBuilder(FILE_SIZE);
            sb.Append("上半段内容:\n");

            int j = 0;
            for (int i = 0; i < FILE_SIZE / 2; i += 2)
            {
                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 / 2; i < FILE_SIZE; i += 2)
            {
                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 == 0)
            {
                lblInfo.Text = "请输入一个字符";
                return;
            }
            char[] chs = textBox2.Text.ToCharArray();
            char ch = chs[0];

            for (int i = 0; i < FILE_SIZE / 2; i += 2)
                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 = 1024 * 1024;
        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>(0, ref data);
                lblInfo.Text = "数据已经保存到内存文件中";
            }
            catch (Exception ex)
            {
                lblInfo.Text = ex.Message;
            }
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            accessor.Read<MyStructure>(0, 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 = 1024 * 1024 * 10;  

        /// <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(0, 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(0, 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();
        }
    }
}
时间: 2024-10-10 15:32:44

C#内存映射文件学习[转]的相关文章

(转)虚拟内存与内存映射文件区别与联系

虚拟内存与内存映射文件是操作系统内存管理的重要部分,二者有相似也有不同的地方,本文是作者学习与应用中得到的一些体会,有错误的地方,请提点. 二者的联系:虚拟内存与内存映射文件都是将一部分内容加载的内存,另一部分放在磁盘(硬盘)上的一种机制.二者都是应用程序动态性的基础.由于二者的虚拟性,对于应用而言,都是透明的. 学过操作系统的都知道虚拟内存其实就是磁盘的一部分,是计算机RAM与硬盘的数据交换区.因为实际的物理内存可能远小于进程的地址空间,这就需要把内存中暂时不用到的数据放到硬盘上一个特殊的地方

Thinking in java(内存映射文件)

在处理大文件时,如果利用普通的FileInputStream 或者FileOutputStream 抑或RandomAccessFile 来进行频繁的读写操作,都将导致进程因频繁读写外存而降低速度.如下为一个对比实验. package test; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOExc

Java利用内存映射文件实现按行读取文件

我们知道内存映射文件读取是各种读取方式中速度最快的,但是内存映射文件读取的API里没有提供按行读取的方法,需要自己实现.下面就是我利用内存映射文件实现按行读取文件的方法,如有错误之处请指出,或者有更好更快的实现方式麻烦也提供一下代码. 代码如下: public class testMemoryMappedFile { public static void main(String[] agrs) throws IOException{ RandomAccessFile memoryMappedFi

内存映射文件

一段内存地址空间,映射着物理存储器上一个已经存在于磁盘上的文件.在对该文件进行操作之前必须首先对文件进行映射.使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作. 内存映射文件,是由一个文件到一块内存的映射.Win32提供了允许应用程序把文件映射到一个进程的函数 (CreateFileMapping). API: HANDLE CreateFileMapping(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttribute

随机访问文件RandomAccessFile 与 内存映射文件MappedByteBuffer

一.RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系

C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转

原文:C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). 内存映射文件对于托管世界的开发人员来说似乎很陌生,但它确实已经是很远古的技术了,而且在操作系统中地位相当.实际上,任何想要共享数据的通信模型都会在幕后使用它. 内存映射文件究竟是个什么?内存映射文件允许你保留一块地址空间,然后将该物理存储映射到这块内存空间中进行操作.物理存储是文件管理,而内存

VC++ 中使用内存映射文件处理大文件

摘要: 本文给出了一种方便实用的解决大文件的读取.存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍. 引言 文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile().WriteFile().ReadFile()和MFC提供的CFile类等.一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB.几百GB.乃至几TB的海量存储,再以通常的文件处理方法进行处

Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)

1.Java直接内存与堆内存-MarchOn 2.Java内存映射文件-MarchOn 3.Java Unsafe的使用-MarchOn 简单总结: 1.内存映射文件 读文件时候一般要两次复制:从磁盘复制到内核空间再复制到用户空间,内存映射文件避免了第二次复制,且内存分配在内核空间,应用程序访问的就是操作系统的内核内存空间,因此极大提高了读取效率.写文件同理. 2.堆内存分配与直接内存分配: Java申请空间时通常是从JVM堆内存分配的,即 ByteBuffer.allocate(int cap

利用内存映射文件在两个进程间共享数据 转

private hMapFile: THandle; MapFilePointer: Pointer; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin hMapFile := CreateFileMapping ( $FFFFFFFF, // 特殊内存映射句柄 nil, page_