內存映射文件


內存映射文件[1][2]

2015-03-31

原理
  有兩種類型的內存映射文件
  進程、視圖和管理內存
內存映射文件對象及其成員
示例
  示例1:在同一進程內同時讀寫同一內存映射文件
  示例2:使用內存映射文件在進程間傳送值類型數據
  示例3:利用序列化技術通過內存映射文件實現進程通訊
參考

原理[1]


 返回

內存映射文件包含虛擬內存中文件的內容。 利用文件與內存空間之間的映射,應用程序(包括多個進程)可以通過直接在內存中進行讀寫來修改文件。 從 .NET Framework 4開始,可以使用托管代碼按照本機Windows函數訪問內存映射文件的方式來訪問內存映射文件

內存映射文件與虛擬內存有些類似,通過內存映射文件可以保留一個地址空間的區域,同時將物理存儲器提交給此區域,只是內存文件映射的物理存儲器來自一個已經存在於磁盤上的文件,而非系統的頁文件,而且在對該文件進行操作之前必須首先對文件進行映射,就如同將整個文件從磁盤加載到內存。由此可以看出,使用內存映射文件處理存儲於磁盤上的文件時,將不必再對文件執行I/O操作,這意味着在對文件進行處理時將不必再為文件申請並分配緩存,所有的文件緩存操作均由系統直接管理,由於取消了將文件數據加載到內存、數據從內存到文件的回寫以及釋放內存塊等步驟,使得內存映射文件在處理大數據量的文件時能起到相當重要的作用。[2]

有兩種類型的內存映射文件

  • 持久內存映射文件:持久文件是與磁盤上的源文件關聯的內存映射文件。  在最后一個進程使用完此文件后,數據將保存到磁盤上的源文件中。 這些內存映射文件適合用來處理非常大的源文件。
  • 非持久內存映射文件:非持久文件是未與磁盤上的源文件關聯的內存映射文件。  當最后一個進程使用完此文件后,數據將丟失,並且垃圾回收功能將回收此文件。 這些文件適用於為進程間通信 (IPC) 創建共享內存。

進程、視圖和管理內存

  • 內存映射文件可以在多個進程之間進行共享。  進程可以通過使用由創建同一內存映射文件的進程所指派的公用名來映射到此文件。
  • 若要使用一個內存映射文件,則必須創建該內存映射文件的完整視圖或部分視圖。  還可以創建內存映射文件的同一部分的多個視圖,進而創建並發內存。 為了使兩個視圖能夠並發,必須基於同一內存映射文件創建這兩個視圖。
  • 如果文件大於應用程序用於內存映射的邏輯內存空間(在 32 位計算機上為 2 GB),則還需要使用多個視圖。 
  • 有兩種類型的視圖:流訪問視圖和隨機訪問視圖。  使用流訪問視圖可對文件進行順序訪問;對於非持久文件和 IPC,這是建議的方法。 在使用持久文件時,隨機訪問視圖是首選方法。
  • 由於內存映射文件是通過操作系統的內存管理器訪問的,因此會自動將此文件分隔為多個頁,並根據需要對其進行訪問。  您不需要自行處理內存管理。

下圖演示多個進程如何同時具有對同一內存映射文件的多個重疊視圖:

Figure 1 內存映射文件的多個重疊視圖 

內存映射文件對象及其成員


 返回

表1:有關使用內存映射文件對象及其成員

方法 說明
MemoryMappedFile.CreateFromFile 磁盤上的文件中獲取表示持久內存映射文件的 MemoryMappedFile 對象。

MemoryMappedFile.CreateNew

或MemoryMappedFile.CreateOrOpen

獲取表示非持久內存映射文件(與磁盤上的文件不關聯)的 MemoryMappedFile 對象。
MemoryMappedFile.OpenExisting 獲取現有內存映射文件(持久文件或非持久文件)的 MemoryMappedFile 對象。
MemoryMappedFile.CreateViewStream 獲取針對內存映射文件的順序訪問視圖的 UnmanagedMemoryStream 對象。
MemoryMappedFile.CreateViewAccessor 獲取針對內存映射文件的隨機訪問視圖的 UnmanagedMemoryAccessor 對象。 

示例[2]


 返回

示例1:在同一進程內同時讀寫同一內存映射文件

Figure 2 在同一進程內同時讀寫同一內存映射文件

示例1代碼如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 using System.IO;  
 11 using System.IO.MemoryMappedFiles;
 12 
 13 namespace MemoryMappingFile
 14 {
 15     public partial class Form1 : Form
 16     {
 17         public Form1()  
 18        {  
 19            InitializeComponent();  
 20            CreateMemoryMapFile();  
 21        }  
 22        private const int FILE_SIZE = 512;  
 23        /// <summary>  
 24        /// 引用內存映射文件  
 25        /// </summary>  
 26        private MemoryMappedFile memoryFile = null;  
 27        /// <summary>  
 28        /// 用於訪問內存映射文件的存取對象  
 29        /// </summary>  
 30        private MemoryMappedViewAccessor accessor1, accessor2,accessor;  
 31        /// <summary>  
 32        /// 創建內存映射文件  
 33        /// </summary>  
 34        private void CreateMemoryMapFile()  
 35        {  
 36            try  
 37            {       
 38                memoryFile = MemoryMappedFile.CreateFromFile("MyFile.dat", FileMode.OpenOrCreate, "MyFile", FILE_SIZE);                 
 39                //訪問文件前半段  
 40                accessor1 = memoryFile.CreateViewAccessor(0, FILE_SIZE / 2);              
 41                //訪問文件后半段  
 42                accessor2 = memoryFile.CreateViewAccessor(FILE_SIZE / 2, FILE_SIZE / 2);                
 43                //訪問全部文件  
 44                accessor = memoryFile.CreateViewAccessor();  
 45                //InitFileContent();  
 46                lblInfo.Text = "內存文件創建成功";  
 47                ShowFileContents();  
 48            }  
 49            catch (Exception ex)  
 50            {  
 51                lblInfo.Text = ex.Message;  
 52            }  
 53        }  
 54        /// <summary>  
 55        /// 關閉並釋放資源  
 56        /// </summary>  
 57        private void DisposeMemoryMapFile()  
 58        {  
 59            if (accessor1 != null)  
 60                accessor1.Dispose();  
 61            if (accessor2 != null)  
 62                accessor2.Dispose();  
 63            if (memoryFile != null)  
 64                memoryFile.Dispose();  
 65        }  
 66  
 67        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)  
 68        {  
 69            DisposeMemoryMapFile();  
 70        }  
 71  
 72        private void btnWrite1_Click(object sender, EventArgs e)  
 73        {  
 74            if (textBox1.Text.Length == 0)  
 75            {  
 76                lblInfo.Text = "請輸入一個字符";  
 77                return;  
 78            }  
 79            char[] chs = textBox1.Text.ToCharArray();  
 80            char ch = chs[0];  
 81             
 82            for (int i = 0; i < FILE_SIZE / 2; i += 2)  
 83                accessor1.Write(i, ch);  
 84              
 85            lblInfo.Text = "字符“" + ch + "”已寫到文件前半部份";  
 86            ShowFileContents();  
 87        }  
 88  
 89        private void btnShow_Click(object sender, EventArgs e)  
 90        {  
 91            ShowFileContents();  
 92        }  
 93  
 94        /// <summary>  
 95        /// 初始化文件內容為可視的字符“0”  
 96        /// </summary>  
 97        private void InitFileContent()  
 98        {  
 99            for (int i = 0; i < FILE_SIZE; i += 2)   
100                 accessor.Write(i,'0');  
101         }  
102         /// <summary>  
103         /// 顯示文件內容  
104         /// </summary>  
105         private void ShowFileContents()  
106         {  
107             StringBuilder sb = new StringBuilder(FILE_SIZE);  
108             sb.Append("上半段內容:\n");  
109   
110             int j = 0;  
111             for (int i = 0; i < FILE_SIZE / 2; i += 2)  
112             {  
113                 sb.Append("\t");  
114                 char ch = accessor.ReadChar(i);  
115                 sb.Append(j);  
116                 sb.Append(":");  
117                 sb.Append(ch);  
118                 j++;  
119             }  
120             sb.Append("\n下半段內容:\n");  
121   
122             for (int i = FILE_SIZE / 2; i < FILE_SIZE; i += 2)  
123             {  
124                 sb.Append("\t");  
125                 char ch = accessor.ReadChar(i);  
126                 sb.Append(j);  
127                 sb.Append(":");  
128                 sb.Append(ch);  
129                 j++;  
130             }  
131             richTextBox1.Text = sb.ToString();  
132         }  
133   
134         private void btnWrite2_Click(object sender, EventArgs e)  
135         {  
136             if (textBox2.Text.Length == 0)  
137             {  
138                 lblInfo.Text = "請輸入一個字符";  
139                 return;  
140             }  
141             char[] chs = textBox2.Text.ToCharArray();  
142             char ch = chs[0];  
143   
144             for (int i = 0; i < FILE_SIZE / 2; i += 2)  
145                 accessor2.Write(i, ch);  
146             lblInfo.Text = "字符“" + ch + "”已寫到文件后半部份";  
147             ShowFileContents();  
148         }  
149     }
150 }
View Code

示例2:使用內存映射文件在進程間傳送值類型數據

Figure2 使用內存映射文件在進程間傳送值類型數據

示例2代碼如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 using System.IO.MemoryMappedFiles;  
 11 using System.IO;  
 12 
 13 
 14 namespace MemoryMappingFile
 15 {
 16      /// <summary>  
 17      /// 要共享的數據結構,注意,其成員不能是引用類型  
 18      /// </summary>  
 19      public struct MyStructure  
 20      {  
 21          public int IntValue  
 22          {  
 23              get;  
 24              set;  
 25          }  
 26          public float FloatValue  
 27          {  
 28              get;  
 29              set;  
 30          }   
 31      }   
 32 
 33 
 34     public partial class Form2 : Form
 35     {
 36         public Form2()  
 37        {  
 38            InitializeComponent();  
 39            InitMemoryMappedFile();  
 40        }  
 41  
 42        /// <summary>  
 43        /// 內存映射文件的容量  
 44        /// </summary>  
 45        private const int FileSize = 1024 * 1024;  
 46        private MemoryMappedFile file = null;  
 47        private MemoryMappedViewAccessor accessor = null;  
 48  
 49        /// <summary>  
 50        /// 初始化內存映射文件  
 51        /// </summary>  
 52        private void InitMemoryMappedFile()  
 53        {  
 54            file = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess", FileSize);  
 55            accessor = file.CreateViewAccessor();  
 56            lblInfo.Text = "內存文件創建或連接成功";           
 57        }  
 58  
 59        /// <summary>  
 60        /// 要共享的數據對象  
 61        /// </summary>  
 62        private MyStructure data;  
 63  
 64        /// <summary>  
 65        /// 顯示數據到窗體上  
 66        /// </summary>  
 67        private void ShowData()  
 68        {  
 69            textBox1.Text = data.IntValue.ToString();  
 70            textBox2.Text = data.FloatValue.ToString();  
 71        }  
 72  
 73        /// <summary>  
 74        /// 根據用戶輸入更新數據  
 75        /// </summary>  
 76        private void UpdateData()  
 77        {  
 78            data.IntValue = int.Parse(textBox1.Text);  
 79            data.FloatValue = float.Parse(textBox2.Text);  
 80        }  
 81  
 82        private void btnSave_Click(object sender, EventArgs e)  
 83        {  
 84            try  
 85            {  
 86                UpdateData();  
 87                accessor.Write<MyStructure>(0, ref data);  
 88                lblInfo.Text = "數據已經保存到內存文件中";  
 89            }  
 90            catch (Exception ex)  
 91            {  
 92                lblInfo.Text = ex.Message;  
 93            }  
 94         }  
 95   
 96         private void btnLoad_Click(object sender, EventArgs e)  
 97         {  
 98             accessor.Read<MyStructure>(0, out data);  
 99             ShowData();  
100             lblInfo.Text = "成功從內存文件中提取了數據";  
101         }  
102   
103         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)  
104         {  
105             if (accessor != null)  
106                 accessor.Dispose();  
107             if (file != null)  
108                 file.Dispose();  
109         }  
110     }
111 }
View Code

示例3:利用序列化技術通過內存映射文件實現進程通訊

Figure 3 利用序列化技術通過內存映射文件實現進程通訊

示例3代碼如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 
 10 using System.IO;
 11 using System.IO.MemoryMappedFiles;
 12 using System.Runtime.Serialization;
 13 using System.Runtime.Serialization.Formatters.Binary;
 14 
 15 
 16 namespace MemoryMappingFile
 17 {
 18     
 19     public partial class Form3 : Form
 20     {
 21         public Form3()
 22         {
 23             InitializeComponent();
 24             InitMemoryMappedFile();
 25         }
 26 
 27         [Serializable]
 28         class MyPic
 29         {
 30             public Image pic;
 31             public string picInfo;
 32         }
 33 
 34         /// <summary>  
 35         /// 圖片  
 36         /// </summary>  
 37         private Image bmp
 38         {
 39             get
 40             {
 41                 return pictureBox1.Image;
 42             }
 43             set
 44             {
 45                 pictureBox1.Image = value;
 46             }
 47         }
 48 
 49         /// <summary>  
 50         /// 圖片說明  
 51         /// </summary>  
 52         private string info
 53         {
 54             get
 55             {
 56                 return txtImageInfo.Text;
 57             }
 58             set
 59             {
 60                 txtImageInfo.Text = value;
 61             }
 62         }
 63 
 64         private MemoryMappedFile memoryFile = null;
 65 
 66         private MemoryMappedViewStream stream = null;
 67 
 68         /// <summary>  
 69         /// 最大容量:10M  
 70         /// </summary>  
 71         private const int FileSize = 1024 * 1024 * 10;
 72 
 73         /// <summary>  
 74         /// 創建內存映射文件,獲取其讀寫流  
 75         /// </summary>  
 76         private void InitMemoryMappedFile()
 77         {
 78             try
 79             {
 80                 memoryFile = MemoryMappedFile.CreateOrOpen("UseMMFBetweenProcess2", FileSize);
 81                 stream = memoryFile.CreateViewStream();
 82             }
 83             catch (Exception ex)
 84             {
 85                 MessageBox.Show(ex.Message);
 86                 Close();
 87             }
 88         }
 89         /// <summary>  
 90         /// 釋放相關資源  
 91         /// </summary>  
 92         private void DisposeMemoryMappedFile()
 93         {
 94             if (stream != null)
 95                 stream.Close();
 96             if (memoryFile != null)
 97                 memoryFile.Dispose();
 98         }
 99 
100         private void btnLoadPic_Click(object sender, EventArgs e)
101         {
102             ChooseImageFile();
103         }
104 
105         //選擇圖片  
106         private void ChooseImageFile()
107         {
108             if (openFileDialog1.ShowDialog() == DialogResult.OK)
109             {
110                 bmp = new Bitmap(openFileDialog1.FileName);
111             }
112         }
113         //根據用戶設定的信息創建對象  
114         private MyPic CreateMyPicObj()
115         {
116             MyPic obj = new MyPic();
117             obj.pic = bmp;
118             obj.picInfo = info;
119             return obj;
120         }
121 
122         /// <summary>  
123         /// 將MyPic對象保存到內存映射文件中  
124         /// </summary>  
125         private void SaveToMMF()
126         {
127             try
128             {
129                 MyPic obj = CreateMyPicObj();
130                 IFormatter formatter = new BinaryFormatter();
131                 stream.Seek(0, SeekOrigin.Begin);
132                 formatter.Serialize(stream, obj);
133                 MessageBox.Show("對象已保存到內存映射文件中");
134             }
135             catch (Exception ex)
136             {
137                 MessageBox.Show(ex.Message);
138             }
139         }
140 
141         private void LoadFromMMF()
142         {
143             try
144             {
145                 // CreateMyPicObj();  
146                 IFormatter formatter = new BinaryFormatter();
147                 stream.Seek(0, SeekOrigin.Begin);
148                 MyPic obj = formatter.Deserialize(stream) as MyPic;
149                 if (obj != null)
150                 {
151                     bmp = obj.pic;
152                     info = obj.picInfo;
153                 }
154             }
155             catch (Exception ex)
156             {
157                 MessageBox.Show(ex.Message);
158             }
159         }
160 
161         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
162         {
163             DisposeMemoryMappedFile();
164         }
165 
166         private void btnSaveToMMF_Click(object sender, EventArgs e)
167         {
168             SaveToMMF();
169         }
170 
171         private void btnLoadFromMMF_Click(object sender, EventArgs e)
172         {
173             LoadFromMMF();
174         }
175 
176 
177     }
178 }
View Code

 

參考

[1] C#內存映射文件學習

[2] 內存映射文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM