Trabajar con archivos mapeados en memoria en .Net

El acceso a archivos es una operación que consume muchos recursos. Acceder a un archivo desde el disco para una aplicación es una operación que requiere mucho tiempo y acceder a los datos desde la memoria primaria siempre es más rápido. Entonces, ¿qué pasa si los archivos de disco que su aplicación necesita leer o escribir residen en la memoria? Aquí es exactamente donde encaja el concepto de archivos mapeados en memoria. En este artículo, exploraremos cómo podemos trabajar con archivos mapeados en memoria en .Net.

Presentación de archivos mapeados en memoria

Un archivo mapeado en memoria es un objeto del kernel que se utiliza para mapear un archivo en su disco a una región en la memoria primaria. Los archivos asignados en memoria pueden tener mayores ganancias de rendimiento en comparación con el acceso directo al disco cuando se trabaja con una gran cantidad de datos o imágenes grandes. Los archivos asignados en memoria han sido parte de la API de Win32, pero hasta hace poco, estaba restringido a usar C ++ o PInvoke para escribir código que aprovecha los archivos asignados en memoria en su aplicación. Sin embargo, con .Net Framework 4 ahora puede trabajar con archivos asignados en memoria directamente desde sus aplicaciones .Net; el tiempo de ejecución ahora le proporciona un contenedor administrado con todas las clases de contenedor necesarias para llamar a la API de Win32. El MSDN dice: "Un archivo mapeado en memoria contiene el contenido de un archivo en la memoria virtual. Esta asignación entre un archivo y el espacio de memoria habilita una aplicación, incluidos varios procesos,para modificar el archivo leyendo y escribiendo directamente en la memoria ".

¿Por qué necesita archivos mapeados en memoria?

Los archivos mapeados en memoria son una buena opción cuando necesita trabajar con una gran cantidad de datos y desea evitar el costo asociado con la clasificación y la eliminación de la clasificación al compartir datos a través de los límites del proceso. Los archivos asignados en memoria son excelentes para procesar un archivo grande; leer un archivo grande es una operación que requiere muchos recursos. Con los archivos asignados en memoria, puede asignar una parte específica de su archivo a la memoria y realizar operaciones de E / S con ese bloque para acelerar el acceso.

Un archivo mapeado en memoria le permite reservar un rango de direcciones de memoria y usar un archivo de disco como almacenamiento físico para la dirección reservada. En otras palabras, le permite reservar un espacio en la memoria y luego asignar almacenamiento físico a esa región. Esto le permite acceder a los datos del disco sin necesidad de realizar operaciones de E / S de archivos. Los archivos asignados en memoria también le permiten compartir datos en múltiples procesos. El sistema operativo se encarga de administrar la memoria para los archivos mapeados en memoria; no necesita preocuparse por cómo se particiona y administra el archivo en páginas. También puede aplicar seguridad en su archivo mapeado en memoria utilizando la enumeración MemoryMappedFileAccess como parámetro al crear el archivo mapeado en memoria. 

Archivos mapeados de memoria persistentes y no persistentes

Básicamente, existen dos tipos de archivos mapeados en memoria. Estos son:

Persistente : los archivos mapeados de memoria persistente son aquellos que están asociados con un archivo de origen en el disco de su sistema. Cuando trabaja con estos tipos de archivos asignados en memoria, los datos se conservan en el disco después de que el último proceso que trabajó en el archivo finalice su actividad.

No persistente : los archivos mapeados en memoria no persistente son aquellos que no están asociados con un archivo de disco. Cuando trabaja con este tipo de archivos asignados en memoria, los datos no se conservan después de que el último proceso que trabajó en el archivo haya terminado su trabajo. Los archivos mapeados en memoria no persistente son excelentes para compartir memoria para comunicaciones entre procesos.

Crear archivos mapeados de memoria persistente

Para crear un archivo mapeado de memoria persistente, debe utilizar el método CreateFromFile de la clase MemoryMappedFile. La clase MemorymappedFile está presente en el espacio de nombres System.IO.MemoryMappedFiles.

El siguiente fragmento de código utiliza el método CreateFromFile para crear un archivo asignado en memoria. A continuación, crea una vista asignada en memoria a una parte del archivo.

static long offset = 0x10000000; // 256 megabytes

static long length = 0x20000000; // 512 megabytes

        static void Main()

        {

            using (var memoryMappedFile = MemoryMappedFile.CreateFromFile("F:\\ImageData.png", FileMode.Open, "PartitionA"))

            {

                using (var accessor = memoryMappedFile.CreateViewAccessor(offset, length))

                {

                    //Other code

                }

            }

        } 

El fragmento de código que se proporciona a continuación muestra cómo puede leer datos de un archivo mapeado en memoria.

using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile("F:\\LargeData.dat"))

            {

                using (MemoryMappedViewStream memoryMappedViewStream = memoryMappedFile.CreateViewStream(0, 1204, MemoryMappedFileAccess.Read))

                {

                    var contentArray = new byte[1024];

                    memoryMappedViewStream.Read(contentArray, 0, contentArray.Length);

                    string content = Encoding.UTF8.GetString(contentArray);

                }

            }

Crear archivos mapeados en memoria no persistente

Para crear archivos mapeados en memoria no persistentes, es decir, archivos que no están mapeados a un archivo existente en el disco, necesita aprovechar los métodos CreateNew y CreateOrOpen.

El siguiente fragmento de código ilustra cómo se puede crear un archivo mapeado en memoria no persistente.

using(MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateNew("idg.txt", 5))

            {

                using(MemoryMappedViewAccessor memoryMappedViewAccessor = memoryMappedFile.CreateViewAccessor())

                {

                var data = new[] { (byte)'I', (byte)'D', (byte)'G'};

                for (int i = 0; i < data.Length; i++)

                    memoryMappedViewAccessor.Write(i, data[i]);

                memoryMappedViewAccessor.Dispose();

                memoryMappedFile.Dispose();

                }

            }

Puede obtener más información sobre los archivos asignados en memoria en este artículo de MSDN.