【C#】Span<T>構造体を使ったバイナリファイルの読み書き

.NET Core 時代になって Span 構造体が追加されて、FileStream クラスとか BitConverter が標準で対応し始めたのでバイナリデータの効率的な入出力が簡単になってるようなので実験。

  • 条件
    • バイナリデータで float 型を5件書き込んだファイルを用意する
    • そのファイルを Span 対応のAPIで読みだす
      • FileStreamクラス
      • Bitconverterクラス
string filePath = @"d:\file.bin";
int len = 5;

// ファイルに20件分のfloatデータを書き出す
using (var wfs = new FileStream(filePath, FileMode.OpenOrCreate))
{
    Random r = new Random();
    for (int i = 0; i < len; i++)
    {
        float value = (float)(r.Next() / 100.0);
        Console.WriteLine($"in, [{i}] {value}");
        wfs.Write(BitConverter.GetBytes(value));
    }
}

// 20件分のデータを読みだす
using var fs = new FileStream(@"d:\file.bin", FileMode.Open);

for (int i = 0; i < len; i++) {

    byte[] buff = new byte[4]; // => 32bit浮動小数の4バイト
    Span<byte> span = new Span<byte>(buff);

    fs.Read(span); // span の大きさ分ファイルからデータを読み取る

    float value = BitConverter.ToSingle(buff);
    Console.WriteLine($"out, [{i}] {value}");
}

このシーケンシャルに読み込むファイルを一度バッファーに読み込むときに for 文を使う必要が無い。

それどころか大きさをリテラルで書く必要すらない。ファイルのポジションも意識しないでOK。

// こういうコードを書く必要が無い
fs.Read(buff, i * 4, buff.Length);

すごく簡単。