.Netでメモリマップトファイルを操作する

ファイルアクセスは、リソースを大量に消費する操作です。アプリケーションのディスクからファイルにアクセスするのは時間のかかる操作であり、プライマリメモリからのデータへのアクセスは常に高速です。では、アプリケーションが読み取りまたは書き込みを行う必要のあるディスクファイルがメモリに存在する場合はどうなるでしょうか。これはまさにメモリマップトファイルの概念が当てはまるところです。この記事では、.Netでメモリマップトファイルを操作する方法について説明します。

メモリマップトファイルの紹介

メモリマップトファイルは、ディスク内のファイルをプライマリメモリ内の領域にマップするために使用されるカーネルオブジェクトです。メモリマップトファイルは、大量のデータや大きなイメージを処理する場合、直接ディスクアクセスと比較してパフォーマンスが大幅に向上する可能性があります。メモリマップトファイルはWin32APIの一部でしたが、最近まで、アプリケーションでメモリマップトファイルを活用するコードを記述するためにC ++またはPInvokeを使用することに制限されていました。ただし、.Net Framework 4では、.Netアプリケーションから直接メモリマップファイルを操作できるようになりました。ランタイムは、Win32APIを呼び出すために必要なすべてのラッパークラスを備えたマネージラッパーを提供するようになりました。 MSDNは次のように述べています。「メモリマップファイルには、仮想メモリ内のファイルの内容が含まれています。ファイルとメモリスペース間のこのマッピングにより、複数のプロセスを含むアプリケーションが可能になります。メモリに直接読み書きすることでファイルを変更します。」

なぜメモリマップトファイルが必要なのですか?

メモリマップトファイルは、大量のデータを処理する必要があり、プロセスの境界を越えてデータを共有する際のマーシャリングとアンマーシャリングに関連するコストを回避したい場合に適しています。メモリマップトファイルは、大きなファイルの処理に優れています。大きなファイルの読み取りは、リソースを大量に消費する操作です。メモリマップトファイルを使用すると、ファイルの特定の部分をメモリにマップし、そのブロックでI / O操作を実行して、アクセスを高速化できます。

メモリマップトファイルを使用すると、ある範囲のメモリアドレスを予約し、予約したアドレスの物理ストレージとしてディスクファイルを使用できます。つまり、メモリ内のスペースを予約してから、その領域に物理ストレージをコミットすることができます。これにより、ファイルI / O操作を実行せずにディスク上のデータにアクセスできます。メモリマップトファイルを使用すると、複数のプロセス間でデータを共有することもできます。オペレーティングシステムは、メモリマップファイルのメモリ管理を処理します。ファイルをページに分割して管理する方法を気にする必要はありません。メモリマップトファイルを作成するときに、MemoryMappedFileAccess列挙体をパラメータとして使用して、メモリマップトファイルにセキュリティを適用することもできます。 

永続的および非永続的なメモリマップファイル

メモリマップトファイルには、基本的に2つのタイプがあります。これらは:

永続:永続メモリマップファイルは、システムのディスク内のソースファイルに関連付けられているファイルです。これらのタイプのメモリマップファイルを操作する場合、ファイルで作業している最後のプロセスがそのアクティビティを終了した後、データはディスクに保持されます。

非永続的:非永続的メモリマップファイルは、ディスクファイルに関連付けられていないファイルです。これらのタイプのメモリマップファイルを操作する場合、ファイルで作業している最後のプロセスが作業を終了した後、データは保持されません。非永続メモリマップファイルは、プロセス間通信用のメモリ共有に最適です。

永続メモリマップファイルの作成

永続的なメモリマップファイルを作成するには、MemoryMappedFileクラスのCreateFromFileメソッドを使用する必要があります。MemorymappedFileクラスは、System.IO.MemoryMappedFiles名前空間に存在します。

次のコードスニペットは、CreateFromFileメソッドを使用してメモリマップファイルを作成します。次に、ファイルの一部にメモリマップされたビューを作成します。

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

                }

            }

        } 

次に示すコードスニペットは、メモリマップファイルからデータを読み取る方法を示しています。

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

                }

            }

非永続メモリマップファイルの作成

非永続的なメモリマップファイル、つまりディスク上の既存のファイルにマップされていないファイルを作成するには、CreateNewメソッドとCreateOrOpenメソッドを利用する必要があります。

次のコードスニペットは、非永続的なメモリマップファイルを作成する方法を示しています。

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

                }

            }

このMSDNの記事から、メモリマップファイルについて詳しく知ることができます。