記憶體對應檔案Memory-Mapped Files

記憶體對應檔案包含檔案在虛擬記憶體中的內容。A memory-mapped file contains the contents of a file in virtual memory. 檔案和記憶體空間之間的這個對應可讓應用程式 (包括多個處理序) 透過直接讀取和寫入記憶體來修改檔案。This mapping between a file and memory space enables an application, including multiple processes, to modify the file by reading and writing directly to the memory. 從 .NET Framework 4 開始,您可以利用與原生 Windows 功能存取記憶體對應檔案相同的方法,使用受控程式碼來存取記憶體對應檔案,如管理記憶體對應檔案 (英文) 所述。Starting with the .NET Framework 4, you can use managed code to access memory-mapped files in the same way that native Windows functions access memory-mapped files, as described in Managing Memory-Mapped Files.

記憶體對應檔案的類型有兩種:There are two types of memory-mapped files:

  • 持續性記憶體對應檔案Persisted memory-mapped files

    持續性檔案是與磁碟上之原始程式檔相關聯的記憶體對應檔案。Persisted files are memory-mapped files that are associated with a source file on a disk. 當最後一個處理序完成檔案處理時,資料就會儲存到磁碟上的原始程式檔。When the last process has finished working with the file, the data is saved to the source file on the disk. 這些記憶體對應檔案適合處理極大的原始程式檔。These memory-mapped files are suitable for working with extremely large source files.

  • 非持續性記憶體對應檔案Non-persisted memory-mapped files

    非持續性檔案是與磁碟上的檔案沒有關聯的記憶體對應檔案。Non-persisted files are memory-mapped files that are not associated with a file on a disk. 當最後一個處理序完成檔案處理時,資料就會遺失,而且該檔案會由記憶體回收進行回收。When the last process has finished working with the file, the data is lost and the file is reclaimed by garbage collection. 這些檔案適合為處理序間通訊 (IPC) 建立共用記憶體。These files are suitable for creating shared memory for inter-process communications (IPC).

處理序、檢視和管理記憶體Processes, Views, and Managing Memory

記憶體對應檔案可以跨多個處理序共用。Memory-mapped files can be shared across multiple processes. 處理序可以使用建立檔案之處理序所指派的一般名稱,對應至相同的記憶體對應檔案。Processes can map to the same memory-mapped file by using a common name that is assigned by the process that created the file.

若要處理記憶體對應檔案,您必須建立整個或部分記憶體對應檔案的檢視。To work with a memory-mapped file, you must create a view of the entire memory-mapped file or a part of it. 您也可以對記憶體對應檔案的相同部分建立多個檢視,藉此建立並行記憶體。You can also create multiple views to the same part of the memory-mapped file, thereby creating concurrent memory. 若要讓兩個檢視維持並行,必須從相同的記憶體對應檔案建立這兩個檢視。For two views to remain concurrent, they have to be created from the same memory-mapped file.

如果檔案大於可用於記憶體對應 (在 32 位元電腦上為 2 GB) 的應用程式邏輯記憶體空間大小,也可能需要多個檢視。Multiple views may also be necessary if the file is greater than the size of the application’s logical memory space available for memory mapping (2 GB on a 32-bit computer).

檢視有兩種:資料流存取檢視和隨機存取檢視。There are two types of views: stream access view and random access view. 將資料流存取檢視用於循序存取檔案;建議將此種方式用於非持續性檔案和 IPC。Use stream access views for sequential access to a file; this is recommended for non-persisted files and IPC. 若要處理持續性檔案,建議使用隨機存取檢視。Random access views are preferred for working with persisted files.

記憶體對應檔案是透過作業系統的記憶體管理員存取的,因此檔案會被自動分割成多頁並視需要進行存取。Memory-mapped files are accessed through the operating system’s memory manager, so the file is automatically partitioned into a number of pages and accessed as needed. 您不必自行處理記憶體管理。You do not have to handle the memory management yourself.

下圖顯示多個處理序如何同時對相同的記憶體對應檔案擁有多個重疊的檢視。The following illustration shows how multiple processes can have multiple and overlapping views to the same memory-mapped file at the same time.

下圖顯示對記憶體對應檔案的多個重疊檢視:The following image shows multiple and overlapped views to a memory-mapped file:

將檢視顯示為記憶體對應檔案的螢幕擷取畫面。

使用記憶體對應檔案進行程式設計Programming with Memory-Mapped Files

下表提供使用記憶體對應檔案物件及其成員的指南。The following table provides a guide for using memory-mapped file objects and their members.

工作Task 要使用的方法或屬性Methods or properties to use
從磁碟上的檔案取得表示持續性記憶體對應檔案的 MemoryMappedFile 物件。To obtain a MemoryMappedFile object that represents a persisted memory-mapped file from a file on disk. MemoryMappedFile.CreateFromFile 方法。MemoryMappedFile.CreateFromFile method.
取得表示非持續性記憶體對應檔案 (與磁碟上的檔案沒有關聯) 的 MemoryMappedFile 物件。To obtain a MemoryMappedFile object that represents a non-persisted memory-mapped file (not associated with a file on disk). MemoryMappedFile.CreateNew 方法。MemoryMappedFile.CreateNew method.

- 或 -- or -

MemoryMappedFile.CreateOrOpen 方法。MemoryMappedFile.CreateOrOpen method.
取得現有記憶體對應檔案 (持續性或非持續性) 的 MemoryMappedFile 物件。To obtain a MemoryMappedFile object of an existing memory-mapped file (either persisted or non-persisted). MemoryMappedFile.OpenExisting 方法。MemoryMappedFile.OpenExisting method.
針對記憶體對應檔案,取得循序存取檢視的 UnmanagedMemoryStream 物件。To obtain a UnmanagedMemoryStream object for a sequentially accessed view to the memory-mapped file. MemoryMappedFile.CreateViewStream 方法。MemoryMappedFile.CreateViewStream method.
針對記憶體對應檔案,取得隨機存取檢視的 UnmanagedMemoryAccessor 物件。To obtain a UnmanagedMemoryAccessor object for a random access view to a memory-mapped fie. MemoryMappedFile.CreateViewAccessor 方法。MemoryMappedFile.CreateViewAccessor method.
取得搭配非受控程式碼 使用的 SafeMemoryMappedViewHandle 物件。To obtain a SafeMemoryMappedViewHandle object to use with unmanaged code. MemoryMappedFile.SafeMemoryMappedFileHandle 屬性。MemoryMappedFile.SafeMemoryMappedFileHandle property.

- 或 -- or -

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle 屬性。MemoryMappedViewAccessor.SafeMemoryMappedViewHandle property.

- 或 -- or -

MemoryMappedViewStream.SafeMemoryMappedViewHandle 屬性。MemoryMappedViewStream.SafeMemoryMappedViewHandle property.
延遲配置記憶體,直到建立檢視 (僅限非持續性檔案) 為止To delay allocating memory until a view is created (non-persisted files only).

(若要判斷目前的系統頁面大小,請使用 Environment.SystemPageSize 屬性)。(To determine the current system page size, use the Environment.SystemPageSize property.)
具有 MemoryMappedFileOptions.DelayAllocatePages 值的 CreateNew 方法。CreateNew method with the MemoryMappedFileOptions.DelayAllocatePages value.

- 或 -- or -

MemoryMappedFileOptions 列舉當作參數的 CreateOrOpen 方法。CreateOrOpen methods that have a MemoryMappedFileOptions enumeration as a parameter.

安全性Security

使用下列採用 MemoryMappedFileAccess 列舉作為參數的方法建立記憶體對應檔案時,您可以套用存取權限:You can apply access rights when you create a memory-mapped file, by using the following methods that take a MemoryMappedFileAccess enumeration as a parameter:

您可以使用採用 MemoryMappedFileRights 作為參數的 OpenExisting 方法指定存取權限,來開啟現有的記憶體對應檔案。You can specify access rights for opening an existing memory-mapped file by using the OpenExisting methods that take an MemoryMappedFileRights as a parameter.

此外,您還可以加入內含預先定義之存取規則的 MemoryMappedFileSecurity 物件。In addition, you can include a MemoryMappedFileSecurity object that contains predefined access rules.

若要將新的或變更的存取規則套用至記憶體對應檔案,請使用 SetAccessControl 方法。To apply new or changed access rules to a memory-mapped file, use the SetAccessControl method. 若要從現有的檔案擷取存取或稽核規則,請使用 GetAccessControl 方法。To retrieve access or audit rules from an existing file, use the GetAccessControl method.

範例Examples

持續性記憶體對應檔案Persisted Memory-Mapped Files

CreateFromFile 方法會從磁碟上現有的檔案建立記憶體對應檔案。The CreateFromFile methods create a memory-mapped file from an existing file on disk.

下列範例會針對極大檔案的一部分建立記憶體對應檢視,及操作其中的一部分。The following example creates a memory-mapped view of a part of an extremely large file and manipulates a portion of it.

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

下列範例會為另一個處理序開啟相同的記憶體對應檔案。The following example opens the same memory-mapped file for another process.

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

非持續性記憶體對應檔案Non-Persisted Memory-Mapped Files

CreateNewCreateOrOpen 方法會建立非對應至磁碟上現有檔案的記憶體對應檔案。The CreateNew and CreateOrOpen methods create a memory-mapped file that is not mapped to an existing file on disk.

下列範例包含三個不同的處理序 (主控台應用程式),這些處理序會將布林值寫入記憶體對應檔案。The following example consists of three separate processes (console applications) that write Boolean values to a memory-mapped file. 發生下列順序的動作:The following sequence of actions occur:

  1. Process A 會建立記憶體對應檔案,並在其中寫入值。Process A creates the memory-mapped file and writes a value to it.

  2. Process B 會開啟記憶體對應檔案,並在其中寫入值。Process B opens the memory-mapped file and writes a value to it.

  3. Process C 會開啟記憶體對應檔案,並在其中寫入值。Process C opens the memory-mapped file and writes a value to it.

  4. Process A 會讀取並顯示記憶體對應檔案中的值。Process A reads and displays the values from the memory-mapped file.

  5. 使用記憶體對應檔案完成 Process A 之後,檔案會立即由記憶體回收進行回收。After Process A is finished with the memory-mapped file, the file is immediately reclaimed by garbage collection.

若要執行此範例,請執行下列動作:To run this example, do the following:

  1. 編譯應用程式,並開啟三個 [命令提示字元] 視窗。Compile the applications and open three Command Prompt windows.

  2. 在第一個 [命令提示字元] 視窗中,執行 Process AIn the first Command Prompt window, run Process A.

  3. 在第二個 [命令提示字元] 視窗中,執行 Process BIn the second Command Prompt window, run Process B.

  4. 返回 Process A,然後按 ENTER。Return to Process A and press ENTER.

  5. 在第三個 [命令提示字元] 視窗中,執行 Process CIn the third Command Prompt window, run Process C.

  6. 返回 Process A,然後按 ENTER。Return to Process A and press ENTER.

Process A 的輸出如下:The output of Process A is as follows:

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 AProcess 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 BProcess 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 CProcess 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

另請參閱See also