Unity入門

【Unity】Binary(バイナリ)での保存と読み込み方法【BinaryWriter / BinaryReader】

この記事について

本記事ではUnityでのバイナリ保存を解説します。
かつて利用されていた BinaryFormatter はセキュリティ上の理由から非推奨となっており、現在は BinaryWriter / BinaryReader を用いたシンプルな方法がよく使われています。

この記事でわかること

  • バイナリ保存の基本と実装方法(BinaryWriter / BinaryReader)
  • データクラスを定義して保存・読み込みする方法
  • 保存データの確認方法(Format-Hex など)
  • 不要なデータの削除方法

データの保存とは?

Unityで使用できるデータの保存方法は複数あります。以下のサイトを参考にして下さい。

Binary(バイナリ)保存とは?

バイナリ保存とは、データを 0と1のバイト列として直接ファイルに書き込む方法 です。
UnityではBinaryWriterを使って文字列や数値をそのままバイナリ形式で保存し、BinaryReaderを使って同じ順序で読み込むことができます。

JSONのように人間が読めるテキスト形式ではなく、メモ帳で開くと文字化けして内容が確認できません。
そのため改ざんされにくく効率的であり、ゲームのセーブデータや内部的に扱う設定値などに利用されます。

Binary(バイナリ)でデータを扱う

Binary(バイナリ)の準備

まずはヒエラルキーで右クリックをして空のGameObjectを1つ用意します。
・「右クリック」→「Create Empty」

次にスクリプトを作成して先ほどのCreate Emptyにアタッチしてください。

データクラスの作成

まずはシリアライズ対象のクラスを [System.Serializable] で定義します。
※Jsonで保存するため構造体にします。

[System.Serializable]
public class Player_Data
{
    public string Name;
    public int Level;
    public float Score;
}

データを保存する(BinaryWriter)

保存は「BinaryWriter」を用いて保存をしていきます。

using System.IO;
using System.Text;
using UnityEngine;

[System.Serializable]
public class Player_Data
{
    public string Name;
    public int Level;
    public float Score;
}

public class Data_Binary : MonoBehaviour
{
    private string filePath;

    void Start()
    {
        filePath = Path.Combine(Application.persistentDataPath, "playerData.dat");

        Player_Data data = new Player_Data();
        data.Name = "No Name";
        data.Level = 100;
        data.Score = 12.3f;

        // バイナリ保存
        BinarySaveManager.Save(data, filePath);
    }
}

// バイナリ保存・読み込みをまとめたクラス
public static class BinarySaveManager
{
    // 保存処理
    public static void Save(Player_Data data, string filePath)
    {
        using (BinaryWriter writer = new BinaryWriter(File.Open(filePath, FileMode.Create)))
        {
            writer.Write(data.Name);
            writer.Write(data.Level);
            writer.Write(data.Score);
        }
    }

    // 読み込み処理
    public static Player_Data Load(string filePath)
    {
        if (!File.Exists(filePath))
        {
            Debug.LogWarning("セーブデータが存在しません: " + filePath);
            return null;
        }

        Player_Data data = new Player_Data();

        using (BinaryReader reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
        {
            data.Name = reader.ReadString();
            data.Level = reader.ReadInt32();
            data.Score = reader.ReadSingle();
        }
        return data;
    }
}

実行してみる際にバイナリはメモ帳では見えないので保存場所でPower Shellを開き、コマンドで確認します。
コマンド : Format-Hex .\playerData.dat

バイナリの読み方を投稿者は知りませんが、バイナリっぽいものが出てますね。

データを読み込む(ReadAllBytes + FromJson)

次は先ほど保存したバイナリデータを読み込みます。読み込みは「」

using System.IO;
using System.Text;
using UnityEngine;

[System.Serializable]
public class Player_Data
{
    public string Name;
    public int Level;
    public float Score;
}

public class Data_Binary : MonoBehaviour
{
    private string filePath;

    void Start()
    {
        filePath = Path.Combine(Application.persistentDataPath, "playerData.dat");

        Player_Data data = new Player_Data();
        data = BinarySaveManager.Load(filePath);

        Debug.Log("名前: " + data.Name);
        Debug.Log("レベル: " + data.Level);
        Debug.Log("スコア: " + data.Score);
    }
}

// バイナリ保存・読み込みをまとめたクラス
public static class BinarySaveManager
{
    // 保存処理
    public static void Save(Player_Data data, string filePath)
    {
        using (BinaryWriter writer = new BinaryWriter(File.Open(filePath, FileMode.Create)))
        {
            writer.Write(data.Name);
            writer.Write(data.Level);
            writer.Write(data.Score);
        }
    }

    // 読み込み処理
    public static Player_Data Load(string filePath)
    {
        if (!File.Exists(filePath))
        {
            Debug.LogWarning("セーブデータが存在しません: " + filePath);
            return null;
        }

        Player_Data data = new Player_Data();

        using (BinaryReader reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
        {
            data.Name = reader.ReadString();
            data.Level = reader.ReadInt32();
            data.Score = reader.ReadSingle();
        }
        return data;
    }
}

実行してみると、先ほどのよくわからないデータが読みこまれて見やすくなりましたね。

データを削除する

バイナリに限った話ではないですが、不要になったファイルはFile.Deleteで削除可能です。

using System.IO;
using System.Text;
using UnityEngine;

public class Data_Binary : MonoBehaviour
{
    private string filePath;

    void Start()
    {
        filePath = Path.Combine(Application.persistentDataPath, "playerData.dat");

        if (File.Exists(filePath))
        {
            File.Delete(filePath);
            Debug.Log("削除完了");
        }
    }
}

実行してみると、playerData.datファイルが削除されましたね。

注意点

  • BinaryFormatterは非推奨
    かつてよく使われていましたが、セキュリティ上の脆弱性があるため現在は推奨されていません。
  • 順序依存
    BinaryWriter / BinaryReader は 書き込んだ順序通りに読み込む必要があります。
    順序を変えたりデータ構造を変更すると、古いデータが読み込めなくなります。
  • デバッグしにくい
    JSONと違って中身が人間に読めないため、直接編集や確認が難しいです。確認する場合はPowerShellのFormat-Hexのバイナリエディタを使いましょう。
  • 改ざん防止にはならない
    バイナリ保存しても完全なセキュリティ対策にはなりません。重要なデータは暗号化(AESなど)やサーバー側での検証が必要です。

まとめ

  • バイナリ保存は 高速かつ効率的 にデータを扱える
  • 実装は BinaryWriter / BinaryReader を使うのがシンプル
  • データの順序や型を変更すると互換性に問題が出やすいので注意
  • 確認にはFormat-Hexコマンドやバイナリエディタを活用
  • 小規模データや開発初期はJSON効率や難読化を重視するならバイナリが適している