TIL

Today I Learned


Project maintained by gushwell Hosted on GitHub Pages — Theme by mattgraham

バイナリーファイルを構造体に読み込む

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;
    }