メモリマップドファイルを利用する場合にお世話になるUnmanagedMemoryAccessor
とWin APIを用いる場合にお世話になるSystem.Interop.Runtime.Marshalを組み合わせた小物関数です。
using System; using System.Collections.Generic; using System.IO; using System.IO.MemoryMappedFiles; using System.Runtime.InteropServices; using System.Text; using System.Linq; internal static partial class Helper { /// <summary> /// アクセッサーからNUL文字(\0)終端の文字列を読み込みます。 /// </summary> /// <param name="accessor">文字列を読み込むアクセッサー。</param> /// <param name="position">読み込みを開始する位置。</param> /// <param name="encoding">読み込む文字列のエンコーディング。</param> /// <returns>読み込んだ文字列。</returns> public static string ReadNullTerminatedString( this UnmanagedMemoryAccessor accessor, long position, Encoding encoding) { List<byte> nameBuffer = new List<byte>(); for (byte b = accessor.ReadByte(position); b != 0; b = accessor.ReadByte(position)) { nameBuffer.Add(b); position++; } return encoding.GetString(nameBuffer.ToArray()); } /// <summary> /// アクセッサーから構造体を読み込みます。 /// </summary> public static StructType ReadMarshalStructure<StructType>( this UnmanagedMemoryAccessor accessor, long position) { byte[] buffer = new byte[Marshal.SizeOf(typeof(StructType))]; accessor.ReadArray<byte>(position, buffer, 0, buffer.Length); GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { return (StructType)Marshal.PtrToStructure( bufferHandle.AddrOfPinnedObject(), typeof(StructType)); } finally { bufferHandle.Free(); } } /// <summary> /// アクセッサーから連続した構造体の配列を読み込みます。 /// </summary> public static StructType[] ReadMarshalStructureArray<StructType>( this UnmanagedMemoryAccessor accessor, long position, int length) { var buffer = new byte[Marshal.SizeOf(typeof(StructType)) * length]; buffer = new byte[Marshal.SizeOf(typeof(StructType)) * length]; accessor.ReadArray<byte>(position, buffer, 0, buffer.Length); var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { var result = new StructType[length]; for (int i = 0; i < length; i++) { result[i] = (StructType)Marshal.PtrToStructure( new IntPtr(bufferHandle.AddrOfPinnedObject().ToInt64() + Marshal.SizeOf(typeof(StructType)) * i), typeof(StructType)); } return result; } finally { bufferHandle.Free(); } } /// <summary> /// アクセッサーから連続した構造体の配列を条件が満たされる限り読み込みます。 /// </summary> public static StructType[] ReadMarshalStructureArrayWhere<StructType>( this UnmanagedMemoryAccessor accessor, long position, Func<StructType, bool> Predictor) { var result = new List<StructType>(); var buffer = new byte[Marshal.SizeOf(typeof(StructType))]; var bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { for (long i = 0; i < long.MaxValue; i++) { accessor.ReadArray<byte>( position + Marshal.SizeOf(typeof(StructType)) * i, buffer, 0, buffer.Length); StructType s = (StructType)Marshal.PtrToStructure( bufferHandle.AddrOfPinnedObject(), typeof(StructType)); if (!Predictor(s)) break; result.Add(s); } } finally { bufferHandle.Free(); } return result.ToArray(); } }
2021/3/10:この記事は別のブログで投稿した記事を移動したものです。