Сопоставленные в памяти файлы

Отображаемый в память файл содержит содержимое файла в виртуальной памяти. Это сопоставление файла и области памяти позволяет приложению, включая множество процессов, изменять файл путем чтения и записи прямо в память. Начиная с .NET Framework 4, можно использовать управляемый код для доступа к сопоставленным в памяти файлам тем же способом, с помощью которого собственные функции Windows получают доступ к сопоставленным в памяти файлам. Описание см. в разделе Managing Memory-Mapped Files in Win32 в библиотеке MSDN.

Существует два типа сопоставленных в памяти файлов.

  • Постоянные сопоставленные в памяти файлы

    Постоянные файлы являются сопоставленными в памяти файлами, которые связаны с исходным файлом на диске. Данные сохраняются в исходный файл на диск, когда последний процесс закончил работу с файлом. Это сопоставленные в памяти файлы подходят для работы с очень большими исходными файлами.

  • Непостоянные сопоставленные в памяти файлы

    Непостоянные файлы являются сопоставленными в памяти файлами, которые не связаны с исходным файлом на диске. Когда последний процесс закончил работу с файлом, данные утрачиваются и файл удаляется функцией сборки мусора. Такие файлы подходят для создания общей памяти для межпроцессного взаимодействия (IPC).

Процессы, представления и управление памятью

Сопоставленные в памяти файлы могут совместно использоваться несколькими процессами. Процессы могут сопоставляться с одним сопоставленным в памяти файлом с помощью общего имени, которое назначается процессом, создающим файл.

Для работы с сопоставленным в памяти файлом необходимо создать представление всего сопоставленного в памяти файла или его части. Можно также создать несколько представлений одной и той же части сопоставленного в памяти файла, создавая таким образом параллельную память. Чтобы два представления оставались параллельными, они должны быть созданы из одного сопоставленного в памяти файла.

Также может потребоваться использование нескольких представлений, если файл превышает размер пространства логической памяти приложения, доступный для сопоставления памяти (2 ГБ на компьютере с 32-разрядной архитектурой).

Существует два типа представлений: представление потокового доступа и представление произвольного доступа. Необходимо использовать представления потокового доступа для последовательного доступа к файлу; это является предпочтительным для непостоянных файлов и IPC. Представления произвольного доступа являются предпочтительными для работы с постоянными файлами.

Сопоставляемые в памяти файлы являются доступными при помощи диспетчера памяти операционной системы, таким образом файл является автоматически разделенным на множество страниц и доступным при необходимости. Управлять памятью вручную не нужно.

На следующем рисунке показаны несколько представлений и перекрывающие представления одного и того же одновременно сопоставленного в памяти файла.

Несколько представлений и перекрывающие представления сопоставленного в памяти файла

Отображение представлений в размещенном в памяти файле.

Программирование с использованием сопоставленных в памяти файлов

В следующей таблице представлено краткое руководство по использованию объектов сопоставленных в памяти файлов и их членов.

Задача

Использование методов или свойств

Чтобы получить объект 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).

Метод CreateNew со значением MemoryMappedFileOptions.DelayAllocatePages.

- или -

метод CreateOrOpen, имеющий перечисление как параметр MemoryMappedFileOptions.

Безопасность

Можно применять права доступа, когда создается сопоставленный в памяти файл, используя методы MemoryMappedFileAccess, которые принимают перечисление как параметр:

Можно задать права доступа для открытия сопоставленного в памяти файла, используя методы OpenExisting, которые принимают MemoryMappedFileRights как параметр.

Дополнительно, можно включить объект 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 создают сопоставленный в памяти файл, не сопоставленный с существующим файлом на диске.

Следующий пример состоит из трех отдельных процессов (консольных приложений), которые записывают логические значения в сопоставленный в памяти файл. Выполняется приведенная ниже последовательность действий.

  1. Процесс Process A создает сопоставленный в памяти файл и записывает в него значение.

  2. Процесс Process B открывает сопоставленный в памяти файл и записывает в него значение.

  3. Процесс Process C открывает сопоставленный в памяти файл и записывает в него значение.

  4. Процесс Process A считывает и отображает значения из сопоставленного в памяти файла.

  5. После того как процесс Process A закончит работу с сопоставленным в памяти файлом, этот файл немедленно будет уничтожен сборкой мусора.

Для выполнения этого примера выполните следующие действия:

  1. Скомпилируйте приложения и откройте три окна командной строки.

  2. В первом окне командной строки запустите процесс Process A.

  3. Во втором окне командной строки запустите процесс Process B.

  4. Вернитесь к процессу Process A и нажмите клавишу ВВОД.

  5. В третьем окне командной строки запустите процесс Process C.

  6. Вернитесь к процессу Process A и нажмите клавишу ВВОД.

Выходные данные процесса 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

Процесс А

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();
        }
    }
}

Процесс Б

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.");
        }
    }
}

Процесс В

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.");
        }
    }
}

См. также

Другие ресурсы

Файловый и потоковый ввод-вывод