記憶體對應檔案
記憶體對應檔案包含檔案在虛擬記憶體中的內容。 檔案和記憶體空間之間的這個對應可讓應用程式 (包括多個處理序) 透過直接讀取和寫入記憶體來修改檔案。 您可以利用與原生 Windows 功能存取記憶體對應檔案相同的方法,使用 受控碼來存取記憶體對應檔案,如管理記憶體對應檔案 \(英文\) 所述。
記憶體對應檔案的類型有兩種:
持續性記憶體對應檔案
持續性檔案是與磁碟上之原始程式檔相關聯的記憶體對應檔案。 當最後一個處理序完成檔案處理時,資料就會儲存到磁碟上的原始程式檔。 這些記憶體對應檔案適合處理極大的原始程式檔。
非持續性記憶體對應檔案
非持續性檔案是與磁碟上的檔案沒有關聯的記憶體對應檔案。 當最後一個處理序完成檔案處理時,資料就會遺失,而且該檔案會由記憶體回收進行回收。 這些檔案適合為處理序間通訊 (IPC) 建立共用記憶體。
處理序、檢視和管理記憶體
記憶體對應檔案可以跨多個處理序共用。 處理序可以使用建立檔案之處理序所指派的一般名稱,對應至相同的記憶體對應檔案。
若要處理記憶體對應檔案,您必須建立整個或部分記憶體對應檔案的檢視。 您也可以對記憶體對應檔案的相同部分建立多個檢視,藉此建立並行記憶體。 若要讓兩個檢視維持並行,必須從相同的記憶體對應檔案建立這兩個檢視。
如果檔案大於可用於記憶體對應 (在 32 位元電腦上為 2 GB) 的應用程式邏輯記憶體空間大小,也可能需要多個檢視。
檢視有兩種:資料流存取檢視和隨機存取檢視。 將資料流存取檢視用於循序存取檔案;建議將此種方式用於非持續性檔案和 IPC。 若要處理持續性檔案,建議使用隨機存取檢視。
記憶體對應檔案是透過作業系統的記憶體管理員存取的,因此檔案會被自動分割成多頁並視需要進行存取。 您不必自行處理記憶體管理。
下圖顯示多個處理序如何同時對相同的記憶體對應檔案擁有多個重疊的檢視。
下圖顯示對記憶體對應檔案的多個重疊檢視:
使用記憶體對應檔案進行程式設計
下表提供使用記憶體對應檔案物件及其成員的指南。
Task | 要使用的方法或屬性 |
---|---|
從磁碟上的檔案取得表示持續性記憶體對應檔案的 MemoryMappedFile 物件。 | MemoryMappedFile.CreateFromFile 方法。 |
取得表示非持續性記憶體對應檔案 (與磁碟上的檔案沒有關聯) 的 MemoryMappedFile 物件。 | MemoryMappedFile.CreateNew 方法。 - 或 - MemoryMappedFile.CreateOrOpen 方法。 |
取得現有記憶體對應檔案 (持續性或非持續性) 的 MemoryMappedFile 物件。 | MemoryMappedFile.OpenExisting 方法。 |
針對記憶體對應檔案,取得循序存取檢視的 UnmanagedMemoryStream 物件。 | MemoryMappedFile.CreateViewStream 方法。 |
針對記憶體對應檔案,取得隨機存取檢視的 UnmanagedMemoryAccessor 物件。 | MemoryMappedFile.CreateViewAccessor 方法。 |
取得搭配非受控程式碼 使用的 SafeMemoryMappedViewHandle 物件。 | MemoryMappedFile.SafeMemoryMappedFileHandle 屬性。 - 或 - MemoryMappedViewAccessor.SafeMemoryMappedViewHandle 屬性。 - 或 - MemoryMappedViewStream.SafeMemoryMappedViewHandle 屬性。 |
延遲配置記憶體,直到建立檢視 (僅限非持續性檔案) 為止 (若要判斷目前的系統頁面大小,請使用 Environment.SystemPageSize 屬性)。 |
具有 MemoryMappedFileOptions.DelayAllocatePages 值的 CreateNew 方法。 - 或 - 將 MemoryMappedFileOptions 列舉當作參數的 CreateOrOpen 方法。 |
安全性
使用下列採用 MemoryMappedFileAccess 列舉作為參數的方法建立記憶體對應檔案時,您可以套用存取權限:
您可以使用採用 MemoryMappedFileRights 作為參數的 OpenExisting 方法指定存取權限,來開啟現有的記憶體對應檔案。
此外,您還可以加入內含預先定義之存取規則的 MemoryMappedFileSecurity 物件。
若要將新的或變更的存取規則套用至記憶體對應檔案,請使用 SetAccessControl 方法。 若要從現有的檔案擷取存取或稽核規則,請使用 GetAccessControl 方法。
範例
持續性記憶體對應檔案
CreateFromFile 方法會從磁碟上現有的檔案建立記憶體對應檔案。
下列範例會針對極大檔案的一部分建立記憶體對應檢視,及操作其中的一部分。
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 brighter.
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.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)
i += colorSize
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.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);
}
}
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
非持續性記憶體對應檔案
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
Process A
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();
}
}
}
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
Process B
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.");
}
}
}
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
Process C
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.");
}
}
}
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