-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Background and Motivation
.NET had acccess to memory mapped files for a long time but using them either requires unsafe pointers, a BinaryReader|Writer like API or Stream. With the advent of Span one could access them more easily and pass them directly without intermediate copies / buffers to a larger set of APIs.
Proposed API
We would add
namespace System.IO
{
public class MemoryMappedFile : IDisposable
{
+ public MemoryMappedMemoryManager CreateMemoryManager();
+ public MemoryMappedMemoryManager CreateMemoryManager(long offset, int size);
+ public MemoryMappedMemoryManager CreateMemoryManager(long offset, int size, MemoryMappedFileAccess access);
}
+ public class MemoryMappedMemoryManager : MemoryManager<byte>
+ {
+ }
}Unlike most other Span APIs we allow passing long offset and int size in order to work with files larger than 2GB which we cannot directly slice into due to all Span related classes being int length based. If you need to work with files larger than 2GB, you need to call CreateMemoryManager with increasing offsets.
Usage Examples
using MemoryMappedFile file = MemoryMappedFile.CreateFromFile("test.txt");
using MemoryMappedMemoryManager manager = file.CreateMemoryManager();
Memory<byte> memory = manager.Memory;
Console.WriteLine(Encoding.UTF8.GetString(memory.Span));Alternative Designs
We could also add a string.Create like API to the MemoryMappedViewAccessor where MemoryMappedViewAccessor manages the lifecycle and the design ensures that the Span does not outlive the MemoryMappedViewAccessor.
namespace System.IO
{
public class MemoryMappedViewAccessor : IDisposable
{
+ public void UseSpan<TState>(TState state, SpanAction<byte, TState> action);
+ public TResult UseSpan<TState, TResult>(TState state, SpanAction<byte, TState> action);
}which would be used like
using MemoryMappedFile file = MemoryMappedFile.CreateFromFile("test.txt");
using MemoryMappedViewAccessor accessor = file.CreateViewAccessor();
accessor.UseSpan((object)null, (span, state) =>
{
Console.WriteLine(Encoding.UTF8.GetString(span));
});Risks
Low risk as far as only adding APIs is concerned.
Designs that allow the Span to outlive the memory mapped file could encounter an access violation if trying to use the span past that point.