BinaryReaderクラスを利用することでバイナリファイルをFileStreamクラスよりも簡単に読むことができる。
using System.IO;
using var sr = new FileStream(path, FileMode.Open);
var binReader = new BinaryReader(sr);
var size = 256;
byte[] bytes = binReader.ReadBytes(size);
...
BinaryReaderクラスには、ReadBoolean, ReadInt32, ReadDouble などのメソッドがあるので、これらを利用しても良いが、一気に構造体のデータへ変換することも可能。
例えば、以下のようなメソッドを定義する。
以下のようなメソッドを定義。このメソッドは、現在の位置から、現在位置から、構造体Tのサイズだけ読み込み、読み込んだデータを構造体として返す。
拡張メソッドにしたほうが使い勝手は良いと思う。
public static T ReadBlock<T>(BinaryReader binReader) where T : struct
{
var structSize = Marshal.SizeOf(typeof(T));
// 領域をアロケートする
var hglobal = Marshal.AllocHGlobal(structSize);
// ファイルからデータを読み込む
byte[] bytes = binReader.ReadBytes(structSize);
// 読み込んだデータをアロケーションした領域にコピーする
Marshal.Copy(bytes, 0, hglobal, structSize);
// 構造体にマーシャリングする
var structure = Marshal.PtrToStructure<T>(hglobal);
// アンマネージメモリ解放
Marshal.FreeHGlobal(hglobal);
// マーシャリングしたデータを構造体にキャストして返す
return (T)structure;
}
以下は、構造体の定義例。構造体の中に構造体が入れ子になっている。また、配列も含んでいる。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MBType3Block
{
public byte recordType;
public ushort chunkSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
public byte[] filler1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public MBType3Entry[] entries;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MBType3Entry
{
public byte offsetDiv16;
public byte dataLengthDiv16;
public ushort updateCount;
public byte dataLengthMod16;
}