內(nèi)存映射文件是由一個文件到進程地址空間的映射,。
C#提供了允許應(yīng)用程序把文件映射到一個進程的函(MemoryMappedFile.CreateOrOpen),。內(nèi)存映射文件與虛擬內(nèi)存有些類似,通過內(nèi)存映射文件可以保留一個地址空間的區(qū)域,,同時將物理存儲器提交給此區(qū)域,,只是內(nèi)存文件映射的物理存儲器來自一個已經(jīng)存在于磁盤上的文件,而非系統(tǒng)的頁文件,,而且在對該文件進行操作之前必須首先對文件進行映射,,就如同將整個文件從磁盤加載到內(nèi)存。由此可以看出,,使用內(nèi)存映射文件處理存儲于磁盤上的文件時,,將不必再對文件執(zhí)行I/O操作,這意味著在對文件進行處理時將不必再為文件申請并分配緩存,,所有的文件緩存操作均由系統(tǒng)直接管理,,由于取消了將文件數(shù)據(jù)加載到內(nèi)存、數(shù)據(jù)從內(nèi)存到文件的回寫以及釋放內(nèi)存塊等步驟,,使得內(nèi)存映射文件在處理大數(shù)據(jù)量的文件時能起到相當(dāng)重要的作用,。另外,實際工程中的系統(tǒng)往往需要在多個進程之間共享數(shù)據(jù),,如果數(shù)據(jù)量小,,處理方法是靈活多變的,,如果共享數(shù)據(jù)容量巨大,那么就需要借助于內(nèi)存映射文件來進行,。實際上,,內(nèi)存映射文件正是解決本地多個進程間數(shù)據(jù)共享的最有效方法。
共享內(nèi)存是內(nèi)存映射文件的一種特殊情況,,內(nèi)存映射的是一塊內(nèi)存,,而非磁盤上的文件。共享內(nèi)存的主語是進程(Process),,操作系統(tǒng)默認會給每一個進程分配一個內(nèi)存空間,,每一個進程只允許訪問操作系統(tǒng)分配給它的哪一段內(nèi)存,而不能訪問其他進程的,。而有時候需要在不同進程之間訪問同一段內(nèi)存,,怎么辦呢?操作系統(tǒng)給出了創(chuàng)建訪問共享內(nèi)存的API,,需要共享內(nèi)存的進程可以通過這一組定義好的API來訪問多個進程之間共有的內(nèi)存,,各個進程訪問這一段內(nèi)存就像訪問一個硬盤上的文件一樣。而.Net 4.0中引入了System.IO.MemoryMappedFiles命名空間,,這個命名空間的類對windows 共享內(nèi)存相關(guān)API做了封裝,,使.Net程序員可以更方便的使用內(nèi)存映射文件。
內(nèi)存映射文件實現(xiàn)進程間通訊
內(nèi)存映射文件是實現(xiàn)進程通訊的又一種方法,,我們可以通過共享剪貼板,、共享物理文件來實現(xiàn)進程間的數(shù)據(jù)共享,這里我們還可以通過內(nèi)存映射文件來實現(xiàn)共享,,這樣,,文件內(nèi)的數(shù)據(jù)就可以用內(nèi)存讀/寫指令來訪問,而不是用ReadFile和WriteFile這樣的I/O系統(tǒng)函數(shù),,從而提高了文件存取速度。這種方式更加快捷高效,,最適用于需要讀取文件并且對文件內(nèi)包含的信息做語法分析的應(yīng)用程序,,如:對輸入文件進行語法分析的彩色語法編輯器,編譯器等,。這種數(shù)據(jù)共享是讓兩個或多個進程映射同一文件映射對象的視圖,,即它們在共享同一物理存儲頁。這樣,,當(dāng)一個進程向內(nèi)存映射文件的一個視圖寫入數(shù)據(jù)時,,其他的進程立即在自己的視圖中看到變化。
注意:
對文件映射對象要使用同一名字,。
是讓兩個或多個進程映射同一文件映射對象的視圖,,即它們在共享同一物理存儲頁,。這樣,當(dāng)一個進程向內(nèi)存映射文件的一個視圖寫入數(shù)據(jù)時,,其他的進程立即在自己的視圖中看到變化,。但要注意,對文件映射對象要使用同一名字,。
內(nèi)存映射文件使用實例:
1. 在同一進程內(nèi)同時讀寫同一內(nèi)存映射文件
- 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>
- /// 引用內(nèi)存映射文件
- /// </summary>
- private MemoryMappedFile memoryFile = null;
- /// <summary>
- /// 用于訪問內(nèi)存映射文件的存取對象
- /// </summary>
- private MemoryMappedViewAccessor accessor1, accessor2,accessor;
- /// <summary>
- /// 創(chuàng)建內(nèi)存映射文件
- /// </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 = "內(nèi)存文件創(chuàng)建成功";
- ShowFileContents();
- }
- catch (Exception ex)
- {
- lblInfo.Text = ex.Message;
- }
- }
- /// <summary>
- /// 關(guān)閉并釋放資源
- /// </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>
- /// 初始化文件內(nèi)容為可視的字符“0”
- /// </summary>
- private void InitFileContent()
- {
- for (int i = 0; i < FILE_SIZE; i += 2)
- accessor.Write(i,'0');
- }
- /// <summary>
- /// 顯示文件內(nèi)容
- /// </summary>
- private void ShowFileContents()
- {
- StringBuilder sb = new StringBuilder(FILE_SIZE);
- sb.Append("上半段內(nèi)容:\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èi)容:\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. 使用內(nèi)存映射文件在進程間傳送值類型數(shù)據(jù)
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- namespace UseMMFBetweenProcess
- {
- /// <summary>
- /// 要共享的數(shù)據(jù)結(jié)構(gòu),,注意,其成員不能是引用類型
- /// </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>
- /// 內(nèi)存映射文件的容量
- /// </summary>
- private const int FileSize = 1024 * 1024;
- private MemoryMappedFile file = null;
- private MemoryMappedViewAccessor accessor = null;
-
- /// <summary>
- /// 初始化內(nèi)存映射文件
- /// </summary>
- private void InitMemoryMappedFile()
- {
- file = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess", FileSize);
- accessor = file.CreateViewAccessor();
- lblInfo.Text = "內(nèi)存文件創(chuàng)建或連接成功";
- }
-
- /// <summary>
- /// 要共享的數(shù)據(jù)對象
- /// </summary>
- private MyStructure data;
-
- /// <summary>
- /// 顯示數(shù)據(jù)到窗體上
- /// </summary>
- private void ShowData()
- {
- textBox1.Text = data.IntValue.ToString();
- textBox2.Text = data.FloatValue.ToString();
- }
-
- /// <summary>
- /// 根據(jù)用戶輸入更新數(shù)據(jù)
- /// </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 = "數(shù)據(jù)已經(jīng)保存到內(nèi)存文件中";
- }
- catch (Exception ex)
- {
- lblInfo.Text = ex.Message;
- }
- }
-
- private void btnLoad_Click(object sender, EventArgs e)
- {
- accessor.Read<MyStructure>(0, out data);
- ShowData();
- lblInfo.Text = "成功從內(nèi)存文件中提取了數(shù)據(jù)";
- }
-
- private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
- {
- if (accessor != null)
- accessor.Dispose();
- if (file != null)
- file.Dispose();
- }
- }
- }
3. 利用序列化技術(shù)通過內(nèi)存映射文件實現(xiàn)進程通訊
- 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>
- /// 創(chuàng)建內(nèi)存映射文件,獲取其讀寫流
- /// </summary>
- private void InitMemoryMappedFile()
- {
- try
- {
- memoryFile = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess2", FileSize);
- stream = memoryFile.CreateViewStream();
- }
- catch (Exception ex )
- {
- MessageBox.Show(ex.Message);
- Close();
- }
- }
- /// <summary>
- /// 釋放相關(guān)資源
- /// </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);
- }
- }
- //根據(jù)用戶設(shè)定的信息創(chuàng)建對象
- private MyPic CreateMyPicObj()
- {
- MyPic obj = new MyPic();
- obj.pic = bmp;
- obj.picInfo = info;
- return obj;
- }
-
- /// <summary>
- /// 將MyPic對象保存到內(nèi)存映射文件中
- /// </summary>
- private void SaveToMMF()
- {
- try
- {
- MyPic obj = CreateMyPicObj();
- IFormatter formatter = new BinaryFormatter();
- stream.Seek(0, SeekOrigin.Begin);
- formatter.Serialize(stream, obj);
- MessageBox.Show("對象已保存到內(nèi)存映射文件中");
- }
- 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();
- }
- }
- }
|