MemoryMappedFile
This type provides a performance advantage. It is found in the System.IO.MemoryMappedFiles
namespace. It is an abstract
data type.
With MemoryMappedFile
, we put a file into memory. In some cases it allows for better memory management than using arrays. MemoryMappedFile
improves performance of binary file loading.
Let's try just loading a file into a memory mapping. Make sure you create the "test.file" and add some characters to it. Then we load it into a mapping.
ReadByte
method returns zeros after the content of the text file. So we can stop processing when zeros are encountered.using System; using System.IO.MemoryMappedFiles; class Program { static void Main() { using (MemoryMappedFile file = MemoryMappedFile.CreateFromFile("c:\\programs\\test.file")) using (MemoryMappedViewStream stream = file.CreateViewStream()) { while (true) { // Read in byte from the MemoryMappedFile. int result = stream.ReadByte(); // Zero bytes are past the end of the file. if (result == 0) { break; } // Print file data to the console. Console.WriteLine("NUMBER: " + result); char letter = (char)result; Console.WriteLine("LETTER: " + letter); } } } }HELLONUMBER: 72 LETTER: H NUMBER: 69 LETTER: E NUMBER: 76 LETTER: L NUMBER: 76 LETTER: L NUMBER: 79 LETTER: O
This program loads a binary file of 4.37 MB that contains binary data. The file is essentially a grouping of about 1400 smaller files.
FileStream
and then BinaryReader
. It uses MemoryMappedFile
, MemoryMappedStream
, and then BinaryReader
.using System; using System.Diagnostics; using System.IO; using System.IO.MemoryMappedFiles; class Program { static void Main() { const int max = 1; var s1 = Stopwatch.StartNew(); for (int i = 0; i < max; i++) { Test1(); } s1.Stop(); var s2 = Stopwatch.StartNew(); for (int i = 0; i < max; i++) { Test2(); } s2.Stop(); var s3 = Stopwatch.StartNew(); for (int i = 0; i < max; i++) { Test3(); } s3.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) / max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) / max).ToString("0.00 ns")); Console.WriteLine(((double)(s3.Elapsed.TotalMilliseconds * 1000 * 1000) / max).ToString("0.00 ns")); } static void Test1() { // FileStream. using (FileStream file = File.Open("C:\\P.bin", FileMode.Open)) { Read(file); } } static void Test2() { // MemoryMappedFile. using (MemoryMappedFile file = MemoryMappedFile.CreateFromFile("C:\\P.bin")) using (MemoryMappedViewStream stream = file.CreateViewStream()) { Read(stream); } } static void Test3() { // MemoryStream. using (MemoryStream stream = new MemoryStream(File.ReadAllBytes("C:\\P.bin"))) { Read(stream); } } static void Read(Stream stream) { // This method reads in the file-format specific values. using (BinaryReader reader = new BinaryReader(stream)) { int count = reader.ReadInt32(); for (int i = 0; i < count; i++) { string u = reader.ReadString(); int len = reader.ReadInt32(); byte[] b = reader.ReadBytes(len); } } } }9671400.00 ns 6737300.00 ns 6958400.00 ns7246513.00 ns 4726050.00 ns 7294708.00 ns
MemoryMappedFile
is fast. For loading the file only once, MemoryMappedFile
is faster than the other two approaches. The FileStream
approach is the slowest.
MemoryMappedFile
is somewhat less than twice as fast as the other approaches.BinaryReader
.MemoryMappedFile
provides a way to load a file with good performance. It seems to have better performance than FileStream
and also the File.ReadAllBytes
approach.