I need something similar to ReadToEnd or ReadAllBytes to read all of the contents of the MemoryMappedFile using the MappedViewAccessor if I don't know the size of it, how can I do it?
I have searched for it, I have seen this question, but it is not the thing I am looking for:
How can I quickly read bytes from a memory mapped file in .NET?
Edit:
There is a problem, the (int)stream.Length is not giving me the correct length, it rather gives the size of the internal buffer used! I need to refresh this question because it is very pressing.
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. Persisted files are memory-mapped files that are associated with a source file on a disk.
Memory-mapped I/O uses the same address space to address both main memory and I/O devices. The memory and registers of the I/O devices are mapped to (associated with) address values. So a memory address may refer to either a portion of physical RAM, or instead to memory and registers of the I/O device.
A memory-mapped file is a feature of the Windows operating system which allows memory to be shared between two or more processes running on the same machine. It requires much less overhead than other methods of inter-process communication such as remoting or WCF.
A direct byte buffer whose content is a memory-mapped region of a file. Mapped byte buffers are created via the FileChannel. map method. This class extends the ByteBuffer class with operations that are specific to memory-mapped file regions.
Rather use the Stream:
public static Byte[] ReadMMFAllBytes(string fileName)
{
using (var mmf = MemoryMappedFile.OpenExisting(fileName))
{
using (var stream = mmf.CreateViewStream())
{
using (BinaryReader binReader = new BinaryReader(stream))
{
return binReader.ReadBytes((int)stream.Length);
}
}
}
}
This is difficult to answer since there are still many details of your application that you haven't specified, but I think both Guffa's and Amer's answers are still partially correct:
If all of the above would fit your application, then the following should work:
static byte[] ReadMemoryMappedFile(string fileName)
{
long length = new FileInfo(fileName).Length;
using (var stream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite))
{
using (var mmf = MemoryMappedFile.CreateFromFile(stream, null, length, MemoryMappedFileAccess.Read, null, HandleInheritability.Inheritable, false))
{
using (var viewStream = mmf.CreateViewStream(0, length, MemoryMappedFileAccess.Read))
{
using (BinaryReader binReader = new BinaryReader(viewStream))
{
var result = binReader.ReadBytes((int)length);
return result;
}
}
}
}
}
To write the data, you can use this:
private static void WriteData(string fileName, byte[] data)
{
using (var stream = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
using (var mmf = MemoryMappedFile.CreateFromFile(stream, null, data.Length, MemoryMappedFileAccess.ReadWrite, null, HandleInheritability.Inheritable, true))
{
using (var view = mmf.CreateViewAccessor())
{
view.WriteArray(0, data, 0, data.Length);
}
}
stream.SetLength(data.Length); // Make sure the file is the correct length, in case the data got smaller.
}
}
But, by the time you do all of the above you might do just as well to use the file directly and avoid the memory mapping. If mapping it to the filesystem isn't acceptable, then Guffa's answer of encoding the length (or an end marker) in the data itself is probably best.
You can't do that.
A view accessor is created with a minimum size of a system page, which means that it may be larger than the actual file. A view stream is just a stream form of an accessor, so it will also give the same behaviour.
"views are provided in units of system pages, and the size of the view is rounded up to the next system page size"
http://msdn.microsoft.com/en-us/library/dd267577.aspx
The accessor will gladly read and write outside the actual file without throwing an exception. When reading, any bytes outside the file will just be zero. When writing, the bytes written outside the file are just ignored.
To read the file from a memory mapped file with the exact size of the original file, you have to already know that size.
Stream created by MemoryMappedFile has a length aligned to file system page size (usually 4096). You have to get the file size from somewhere else. If it is memory mapped file you could use that code:
byte[] ReadAllMemoryMappedFileBytes(string filePath)
{
var fileInfo = new FileInfo(filePath);
using (var file = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open))
using (var stream = file.CreateViewAccessor())
{
byte[] bytes = new byte[fileInfo.Length];
stream.ReadArray(0, bytes, 0, bytes.Length);
return bytes;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With