原文連接程序員
內存映射文件是由一個文件到進程地址空間的映射。windows
C#提供了容許應用程序把文件映射到一個進程的函(MemoryMappedFile.CreateOrOpen)。內存映射文件與虛擬內存有些相似,經過內存映射文件能夠保留一個地址空間的區域,同時將物理存儲器提交給此區域,只是內存文件映射的物理存儲器來自一個已經存在於磁盤上的文件,而非系統的頁文件,並且在對該文件進行操做以前必須首先對文件進行映射,就如同將整個文件從磁盤加載到內存。由此能夠看出,使用內存映射文件處理存儲於磁盤上的文件時,將沒必要再對文件執行I/O操做,這意味着在對文件進行處理時將沒必要再爲文件申請並分配緩存,全部的文件緩存操做均由系統直接管理,因爲取消了將文件數據加載到內存、數據從內存到文件的回寫以及釋放內存塊等步驟,使得內存映射文件在處理大數據量的文件時能起到至關重要的做用。另外,實際工程中的系統每每須要在多個進程之間共享數據,若是數據量小,處理方法是靈活多變的,若是共享數據容量巨大,那麼就須要藉助於內存映射文件來進行。實際上,內存映射文件正是解決本地多個進程間數據共享的最有效方法。緩存
共享內存是內存映射文件的一種特殊狀況,內存映射的是一塊內存,而非磁盤上的文件。共享內存的主語是進程(Process),操做系統默認會給每個進程分配一個內存空間,每個進程只容許訪問操做系統分配給它的哪一段內存,而不能訪問其餘進程的。而有時候須要在不一樣進程之間訪問同一段內存,怎麼辦呢?操做系統給出了建立訪問共享內存的API,須要共享內存的進程能夠經過這一組定義好的API來訪問多個進程之間共有的內存,各個進程訪問這一段內存就像訪問一個硬盤上的文件同樣。而.Net 4.0中引入了System.IO.MemoryMappedFiles命名空間,這個命名空間的類對windows 共享內存相關API作了封裝,使.Net程序員能夠更方便的使用內存映射文件。數據結構
內存映射文件實現進程間通信app
內存映射文件是實現進程通信的又一種方法,咱們能夠經過共享剪貼板、共享物理文件來實現進程間的數據共享,這裏咱們還能夠經過內存映射文件來實現共享,這樣,文件內的數據就能夠用內存讀/寫指令來訪問,而不是用ReadFile和WriteFile這樣的I/O系統函數,從而提升了文件存取速度。這種方式更加快捷高效,最適用於須要讀取文件而且對文件內包含的信息作語法分析的應用程序,如:對輸入文件進行語法分析的彩色語法編輯器,編譯器等。這種數據共享是讓兩個或多個進程映射同一文件映射對象的視圖,即它們在共享同一物理存儲頁。這樣,當一個進程向內存映射文件的一個視圖寫入數據時,其餘的進程當即在本身的視圖中看到變化。編輯器
注意:函數
對文件映射對象要使用同一名字。大數據
是讓兩個或多個進程映射同一文件映射對象的視圖,即它們在共享同一物理存儲頁。這樣,當一個進程向內存映射文件的一個視圖寫入數據時,其餘的進程當即在本身的視圖中看到變化。但要注意,對文件映射對象要使用同一名字。ui
內存映射文件使用實例:spa
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(); } } }