名古屋出身ソフトウェアエンジニアのブログ

.NET (C#) で複数オブジェクトをストリームに JSON シリアライズ

公開:
更新:

BinaryFormatter が将来的に .NET から削除されるようです(つい最近まで知らなかった勢)。 Python の pickle 同様、低レイヤ API としてあくまでリスクがあっても使えるようにしてあるし、これからもそうであろうと思っていたので驚きました。

破壊的変更:BinaryFormatter シリアル化メソッドが古い形式になり、ASP.NET アプリでは使用不可に - .NET
Core .NET ライブラリにおける .NET 5 の破壊的変更について学習します。BinaryFormatter、Formatter、および IFormatter におけるシリアル化と逆シリアル化メソッドが古いものになりました。

JsonSerializer へ移行すれば良さそうですが、一つのストリームに対して一つのオブジェクトしか保存できず、BinaryFormatter で出来ていた複数オブジェクトを一つのファイルへ書き込むような API が存在しません。

JsonSerializer クラス (System.Text.Json)
オブジェクトまたは値型を JSON にシリアル化したり、JSON をオブジェクトまたは値型に逆シリアル化したりする機能を提供します。

Unity でセーブデータ保存に BinaryFormatter を利用しており、複数オブジェクトを同一ファイルに何も考えず入れていたので、対処法を考えました。

実装

あまりにも普通 (trivial) すぎる方法ですが、ペイロードサイズとペイロードを交互に書き込む実装としました。JsonUtilityUnityEngine から使える JSON シリアライザです(System.Text.Json のものではないです)。

シリアライズ

using (var fs = new FileStream(saveFilePath, FileMode.Create, FileAccess.Write))
{
    var jsonString = JsonUtility.ToJson(saveData);
    var data = Encoding.UTF8.GetBytes(jsonString);
    fs.Write(data, 0, data.Length);
}

デシリアライズ

using (var fs = new FileStream(saveFilePath, FileMode.Open, FileAccess.Read))
{
    byte[] bytes = new byte[fs.Length];
    fs.Read(bytes, 0, bytes.Length);
    var jsonString = Encoding.UTF8.GetString(bytes);
    saveData = JsonUtility.FromJson<JsonSaveData>(jsonString);
}