在某些情况下,MemoryMappedViewAccessor
类不会因为有效读取字节而削减它;我们得到的最好的是通用ReadArray<byte>
,它是所有结构的路由,当你只需要字节时会涉及几个不必要的步骤。
可以使用MemoryMappedViewStream
,但因为它基于Stream
,您需要首先寻找正确的位置,然后读取操作本身会有更多不必要的步骤。
是否有快速,高性能的方法从.NET中的内存映射文件读取字节数组,因为它应该只是地址空间的特定区域才能读取?
答案 0 :(得分:30)
此解决方案需要不安全的代码(使用/unsafe
开关编译),但直接抓取指向内存的指针;然后可以使用Marshal.Copy
。这比.NET框架提供的方法要快得多。
// assumes part of a class where _view is a MemoryMappedViewAccessor object
public unsafe byte[] ReadBytes(int offset, int num)
{
byte[] arr = new byte[num];
byte *ptr = (byte*)0;
this._view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
Marshal.Copy(IntPtr.Add(new IntPtr(ptr), offset), arr, 0, num);
this._view.SafeMemoryMappedViewHandle.ReleasePointer();
return arr;
}
public unsafe void WriteBytes(int offset, byte[] data)
{
byte* ptr = (byte*)0;
this._view.SafeMemoryMappedViewHandle.AcquirePointer(ref ptr);
Marshal.Copy(data, 0, IntPtr.Add(new IntPtr(ptr), offset), data.Length);
this._view.SafeMemoryMappedViewHandle.ReleasePointer();
}
答案 1 :(得分:2)
来自报告:
MemoryMappedViewAccessor有一个SafeMemoryMappedViewHandle属性,它返回MemoryMappedView内部使用的ViewHandle,但没有任何属性可以返回MemoryMappedView使用的偏移量。
由于MemoryMappedView是页面对齐MemoryMappedFile.CreateViewAccessor(offset,size)中请求的偏移量,因此在不知道偏移量的情况下,无法使用SafeMemoryMappedViewHandle进行任何有用的操作。
请注意,我们实际想要做的是使用AcquirePointer(ref byte * pointer)方法来允许运行一些基于快速指针的(可能是非托管的)代码。我们可以将指针对齐页面,但必须能够找出原始请求地址的偏移量。
答案 2 :(得分:1)
此解决方案的安全版本是:
var file = MemoryMappedFile.CreateFromFile(...);
var accessor = file.CreateViewAccessor();
var bytes = new byte[yourLength];
// assuming the string is at the start of the file
// aka position: 0
// https://msdn.microsoft.com/en-us/library/dd267761(v=vs.110).aspx
accessor.ReadArray<byte>(
position: 0, // The number of bytes in the accessor at which to begin reading
array: bytes, // The array to contain the structures read from the accessor
offset: 0, // The index in `array` in which to place the first copied structure
count: yourLength // The number of structures of type T to read from the accessor.
);
var myString = Encoding.UTF8.GetString(bytes);
我测试了这个,它确实有效。我无法评论它的表现,或者它是否是最好的整体解决方案,只是它有效。
答案 3 :(得分:1)
我知道这是一个较旧的问题已经得到解答,但我想补充两分钱。
我使用接受的答案(使用不安全的代码)和MemoryMappedViewStream方法运行测试,以读取200MB字节数组。
<强> MemoryMappedViewStream 强>
describe('Overall Test Suite',function() {
var expectedResult; //global variable for all 'it' blocks inside suite.
it('Should navigate to webpage..', function(){
log.info("Test is being executed..");
login.goTo(parameters.url);
login.login(parameters.username, parameters.password);
});
it('Executing Queries', function(){
expect(helper.executeSelectQuery(query_select)).toBeEqual(expectedResult);//let jasmine resolve the promise implicitly
});
});
我每次接近测试3次并接受以下时间。
MemoryMappedViewStream:
不安全的方法
从少量测试来看, const int MMF_MAX_SIZE = 209_715_200;
var buffer = new byte[ MMF_VIEW_SIZE ];
using( var mmf = MemoryMappedFile.OpenExisting( "mmf1" ) )
using( var view = mmf.CreateViewStream( 0, buffer.Length, MemoryMappedFileAccess.ReadWrite ) )
{
if( view.CanRead )
{
Console.WriteLine( "Begin read" );
sw.Start( );
view.Read( buffer, 0, MMF_MAX_SIZE );
sw.Stop( );
Console.WriteLine( $"Read done - {sw.ElapsedMilliseconds}ms" );
}
}
具有非常轻微的优势。考虑到这一点,对于那些在路上阅读这篇文章的人,我会选择MemoryMappedViewStream
。