記憶體對應檔案
記憶體對應檔案包含檔案在虛擬記憶體中的內容。 這個對應介於檔案與記憶體空間之間,可以讓包含多個處理序的應用程式,直接對記憶體進行讀取和寫入來修改檔案。 從 .NET Framework 4 版 開始,您可以使用 Managed 程式碼,和使用原生 Windows 功能存取記憶體對應檔案一樣來存取記憶體對應檔案,如 MSDN Library 中的在 Win32 中管理記憶體對應檔案 (英文) 所述。
有兩種類型的記憶體對應檔案:
保存的記憶體對應檔案
保存檔是與磁碟上之原始程式檔關聯的記憶體對應檔案。 最後一個處理序處理完檔案時,資料會儲存到磁碟上的原始程式檔。 這些記憶體對應檔案適合用來處理極大的原始程式檔。
非保存的記憶體對應檔案
非保存檔是未與磁碟上之原始程式檔關聯的記憶體對應檔案。 最後一個處理序處理完檔案時,資料會遺失且記憶體回收會收回檔案。 這些檔案適合用來建立處理序間通訊 (IPC) 的共用記憶體。
處理、檢視和管理記憶體
記憶體對應檔案可以供多個處理序共用。 處理序可以利用當初建立記憶體對應檔案的處理序所指派的一般名稱,來對應至相同的記憶體對應檔案。
若要使用記憶體對應檔案,您必須對整個或部分記憶體對應檔案建立檢視。 您也可以對記憶體對應檔案的相同部分建立多個檢視,從而建立並行記憶體。 若要讓兩個檢視保持並行,這兩個檢視必須建立自相同的記憶體對應檔案。
如果檔案大於應用程式用於記憶體對應的邏輯記憶體空間大小 (在 32 位元電腦上為 2 GB),則也可能需要使用多個檢視。
有兩種檢視:資料流存取檢視和隨機存取檢視。 資料流存取檢視會對檔案進行循序存取,對於非保存檔案和 IPC 建議使用這個檢視。 若要使用保存檔案,則建議使用隨機存取檢視。
記憶體對應檔案是透過作業系統的記憶體管理員受到存取,所以檔案會自動分割成多個分頁,並視需要受到存取。 您不需要自己親手管理記憶體。
下圖顯示多個處理序如何才能同時對同一個記憶體對應檔案擁有多個且重疊的檢視。
記憶體對應檔案的多個且重疊的檢視。
使用記憶體對應檔案進行程式設計
下表提供記憶體對應檔案物件和其成員的使用指南。
工作 |
要使用的方法或屬性 |
---|---|
取得 MemoryMappedFile 物件,該物件表示磁碟上之檔案的保存記憶體對應檔案。 |
|
取得 MemoryMappedFile 物件,該物件表示非保存記憶體對應檔案 (與磁碟上的檔案沒有關聯)。 |
MemoryMappedFile.CreateNew 方法呼叫的。 -或- |
取得現有記憶體對應檔案 (保存或非保存) 的 MemoryMappedFile 物件。 |
|
取得 UnmanagedMemoryStream 物件以對記憶體對應檔案進行循序存取檢視。 |
|
取得 UnmanagedMemoryAccessor 物件以對記憶體對應檔案進行隨機存取檢視。 |
|
取得 SafeMemoryMappedViewHandle 物件以使用 Unmanaged 程式碼。 |
MemoryMappedFile.SafeMemoryMappedFileHandle 屬性。 -或- MemoryMappedViewAccessor.SafeMemoryMappedViewHandle 屬性。 -或- |
將記憶體配置延到建立檢視時才進行 (僅限非保存檔案)。 (若要決定目前系統頁面大小,請使用 Environment.SystemPageSize 屬性。) |
具有 MemoryMappedFileOptions.DelayAllocatePages 值的 CreateNew 方法。 -或- 以 MemoryMappedFileOptions 列舉做為參數的 CreateOrOpen 方法。 |
安全性
您可以在建立記憶體對應檔案時套用存取權,方法是使用下列以 MemoryMappedFileAccess 列舉做為參數的方法:
您可以指定開啟現有記憶體對應檔案的存取權,方法是使用以 MemoryMappedFileRights 做為參數的 OpenExisting 方法。
此外,您可以納入包含預先定義之存取規則的 MemoryMappedFileSecurity 物件。
若要將新的或變更的存取規則套用至記憶體對應檔案,請使用 SetAccessControl 方法。 若要從現有檔案擷取存取規則或稽核規則,請使用 GetAccessControl 方法。
範例
保存的記憶體對應檔案
CreateFromFile 方法會從磁碟上的現有檔案建立記憶體對應檔案。
下列範例會對超大檔案的一部分建立記憶體對應檢視,並操作其中一部分。
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices
Class Program
Sub Main()
Dim offset As Long = &H10000000 ' 256 megabytes
Dim length As Long = &H20000000 ' 512 megabytes
' Create the memory-mapped file.
Using mmf = _
MemoryMappedFile.CreateFromFile("c:\ExtremelyLargeImage.data", _
FileMode.Open,"ImgA")
' Create a random access view, from the 256th megabyte (the offset)
' to the 768th megabyte (the offset plus length).
Using accessor = mmf.CreateViewAccessor(offset, length)
Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
Dim color As MyColor
Dim i As Long = 0
' Make changes to the view.
Do While (i < length)
accessor.Read(i, color)
color.Brighten(10)
accessor.Write(i, color)
Loop
End Using
End Using
End Sub
End Class
Public Structure MyColor
Public Red As Short
Public Green As Short
Public Blue As Short
Public Alpha As Short
' Make the view brighter.
Public Sub Brighten(ByVal value As Short)
Red = CType(Math.Min(Short.MaxValue, _
(CType(Red, Integer) + value)), Short)
Green = CType(Math.Min(Short.MaxValue, _
(CType(Green, Integer) + value)), Short)
Blue = CType(Math.Min(Short.MaxValue, _
(CType(Blue, Integer) + value)), Short)
Alpha = CType(Math.Min(Short.MaxValue, _
(CType(Alpha, Integer) + value)), Short)
End Sub
End Structure
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
long offset = 0x10000000; // 256 megabytes
long length = 0x20000000; // 512 megabytes
// Create the memory-mapped file.
using (var mmf =
MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data",
FileMode.Open,"ImgA"))
{
// Create a random access view, from the 256th megabyte (the offset)
// to the 768th megabyte (the offset plus length).
using (var accessor = mmf.CreateViewAccessor(offset, length))
{
int colorSize = Marshal.SizeOf(typeof(MyColor));
MyColor color;
// Make changes to the view.
for (long i = 0; i < length; i += colorSize)
{
accessor.Read(i, out color);
color.Brighten(10);
accessor.Write(i, ref color);
}
}
}
}
public struct MyColor
{
public short Red;
public short Green;
public short Blue;
public short Alpha;
// Make the view brigher.
public void Brighten(short value)
{
Red = (short)Math.Min(short.MaxValue, (int)Red + value);
Green = (short)Math.Min(short.MaxValue, (int)Green + value);
Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
}
}
}
下列範例會為另一個處理序開啟相同的記憶體對應檔案。
Imports System
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices
Class Program
Public Shared Sub Main(ByVal args As String())
' Assumes another process has created the memory-mapped file.
Using mmf = MemoryMappedFile.OpenExisting("ImgA")
Using accessor = mmf.CreateViewAccessor(4000000, 2000000)
Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
Dim color As MyColor
' Make changes to the view.
Dim i As Long = 0
While i < 1500000
accessor.Read(i, color)
color.Brighten(30)
accessor.Write(i, color)
i += colorSize
End While
End Using
End Using
End Sub
End Class
Public Structure MyColor
Public Red As Short
Public Green As Short
Public Blue As Short
Public Alpha As Short
' Make the view brigher.
Public Sub Brighten(ByVal value As Short)
Red = CShort(Math.Min(Short.MaxValue, CInt(Red) + value))
Green = CShort(Math.Min(Short.MaxValue, CInt(Green) + value))
Blue = CShort(Math.Min(Short.MaxValue, CInt(Blue) + value))
Alpha = CShort(Math.Min(Short.MaxValue, CInt(Alpha) + value))
End Sub
End Structure
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
// Assumes another process has created the memory-mapped file.
using (var mmf = MemoryMappedFile.OpenExisting("ImgA"))
{
using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
{
int colorSize = Marshal.SizeOf(typeof(MyColor));
MyColor color;
// Make changes to the view.
for (long i = 0; i < 1500000; i += colorSize)
{
accessor.Read(i, out color);
color.Brighten(20);
accessor.Write(i, ref color);
}
}
}
}
}
public struct MyColor
{
public short Red;
public short Green;
public short Blue;
public short Alpha;
// Make the view brigher.
public void Brighten(short value)
{
Red = (short)Math.Min(short.MaxValue, (int)Red + value);
Green = (short)Math.Min(short.MaxValue, (int)Green + value);
Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
}
}
非保存的記憶體對應檔案
CreateNew 和 CreateOrOpen 方法會建立不對應至磁碟上現有檔案的記憶體對應檔案。
下列範例由三個獨立的處理序 (主控台應用程式) 所組成,這些處理序會將布林值寫入至記憶體對應檔案。 發生的動作序列如下:
Process A 建立記憶體對應檔案並在其中寫入值。
Process B 開啟記憶體對應檔案並在其中寫入值。
Process C 開啟記憶體對應檔案並在其中寫入值。
Process A 從記憶體對應檔案中讀取並顯示值。
在 Process A 完成處理記憶體對應檔案之後,檔案立即由記憶體回收作業回收。
若要執行此範例,請執行下列步驟:
編譯應用程式並開啟三個 [命令提示字元] 視窗。
在第一個命令提示字元視窗中執行 Process A。
在第二個命令提示字元視窗中執行 Process B。
回到 Process A 並按 ENTER 鍵。
在第三個命令提示字元視窗中執行 Process C。
回到 Process A 並按 ENTER 鍵。
Process A 的輸出如下:
Start Process B and press ENTER to continue.
Start Process C and press ENTER to continue.
Process A says: True
Process B says: False
Process C says: True
處理序 A
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1
' Process A:
Sub Main()
Using mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("testmap", 10000)
Dim mutexCreated As Boolean
Dim mTex As Mutex = New Mutex(True, "testmapmutex", mutexCreated)
Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
Dim writer As BinaryWriter = New BinaryWriter(Stream)
writer.Write(1)
End Using
mTex.ReleaseMutex()
Console.WriteLine("Start Process B and press ENTER to continue.")
Console.ReadLine()
Console.WriteLine("Start Process C and press ENTER to continue.")
Console.ReadLine()
mTex.WaitOne()
Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
Dim reader As BinaryReader = New BinaryReader(Stream)
Console.WriteLine("Process A says: {0}", reader.ReadBoolean())
Console.WriteLine("Process B says: {0}", reader.ReadBoolean())
Console.WriteLine("Process C says: {0}", reader.ReadBoolean())
End Using
mTex.ReleaseMutex()
End Using
End Sub
End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
class Program
{
// Process A:
static void Main(string[] args)
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
{
bool mutexCreated;
Mutex mutex = new Mutex(true, "testmapmutex", out mutexCreated);
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(1);
}
mutex.ReleaseMutex();
Console.WriteLine("Start Process B and press ENTER to continue.");
Console.ReadLine();
Console.WriteLine("Start Process C and press ENTER to continue.");
Console.ReadLine();
mutex.WaitOne();
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader reader = new BinaryReader(stream);
Console.WriteLine("Process A says: {0}", reader.ReadBoolean());
Console.WriteLine("Process B says: {0}", reader.ReadBoolean());
Console.WriteLine("Process C says: {0}", reader.ReadBoolean());
}
mutex.ReleaseMutex();
}
}
}
處理序 B
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1
' Process B:
Sub Main()
Try
Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
mTex.WaitOne()
Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(1, 0)
Dim writer As BinaryWriter = New BinaryWriter(Stream)
writer.Write(0)
End Using
mTex.ReleaseMutex()
End Using
Catch noFile As FileNotFoundException
Console.WriteLine("Memory-mapped file does not exist. Run Process A first." & vbCrLf & noFile.Message)
End Try
End Sub
End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
class Program
{
// Process B:
static void Main(string[] args)
{
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
{
Mutex mutex = Mutex.OpenExisting("testmapmutex");
mutex.WaitOne();
using (MemoryMappedViewStream stream = mmf.CreateViewStream(1, 0))
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(0);
}
mutex.ReleaseMutex();
}
}
catch (FileNotFoundException)
{
Console.WriteLine("Memory-mapped file does not exist. Run Process A first.");
}
}
}
處理序 C
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading
Module Module1
' Process C:
Sub Main()
Try
Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
mTex.WaitOne()
Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(2, 0)
Dim writer As BinaryWriter = New BinaryWriter(Stream)
writer.Write(1)
End Using
mTex.ReleaseMutex()
End Using
Catch noFile As FileNotFoundException
Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B." & vbCrLf & noFile.Message)
End Try
End Sub
End Module
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
class Program
{
// Process C:
static void Main(string[] args)
{
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
{
Mutex mutex = Mutex.OpenExisting("testmapmutex");
mutex.WaitOne();
using (MemoryMappedViewStream stream = mmf.CreateViewStream(2, 0))
{
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(1);
}
mutex.ReleaseMutex();
}
}
catch (FileNotFoundException)
{
Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B.");
}
}
}