※ これは 2022/02/03 時点の Unity 2021.2.10f1、MessagePack for C# v2.3.85 の情報です
最新版では動作が異なる可能性がありますのでご注意ください
前回、MessagePack for C# のシリアライズ、デシリアライズができたので、ファイルへの読み書きをやってみる
スポンサードリンク
前回の SaveData.cs
を拡張するためまずは IPersistentData
クラスとその拡張クラスを下記のように追加
シリアライズ・デシリアライズ処理部分を SaveAsync/LoadAsync メソッドにしてファイル入出力処理をするようにした感じ
using Cysharp.Threading.Tasks; using MessagePack; using System; using System.IO; using System.Security; namespace MatatabiUx.Common { /// <summary> /// 永続化データのインタフェース /// </summary> public interface IPersistentData {} /// <summary> /// 永続化データを処理する拡張クラス /// </summary> public static class IPersistentDataExtentions { /// <summary> /// ファイルからデータを読み込む /// </summary> /// <param name="data">読み込むデータモデル</param> /// <param name="path">読み込み先パス</param> /// <typeparam name="T">読み込むデータモデルの型</typeparam> /// <returns>読み込んだデータ、ファイルがなかった場合はデフォルト値</returns> public static async UniTask<T> LoadAsync<T>(this T data, string path) where T : IPersistentData, new() { if (!File.Exists(path)) { return new T(); } try { using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) return await MessagePackSerializer.DeserializeAsync<T>(stream); } catch (IOException) { } catch (UnauthorizedAccessException) { } catch (SecurityException) { } return default; } /// <summary> /// ファイルにデータを書き込む /// </summary> /// <param name="data">書き込むデータモデル</param> /// <param name="path">書き込み先パス</param> /// <typeparam name="T">書き込むデータモデルの型</typeparam> /// <returns>書き込みが成功した場合は true, それ以外は false</returns> public static async UniTask<bool> SaveAsync<T>(this T data, string path) where T : IPersistentData, new() { try { using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)) await MessagePackSerializer.SerializeAsync(stream, data); return true; } catch (IOException) { } catch (UnauthorizedAccessException) { } catch (SecurityException) { } return false; } } }
さらに SaveData.common.cs
として前回のデータ項目を記載したソースファイルとは別ファイルにして下記を記述
共通部分を partial
で分離したのでデータ項目が増えてもこのソースファイルは変更しなくて済む
using Cysharp.Threading.Tasks; using System; using System.IO; using UnityEngine; namespace MatatabiUx.Common { public partial class SaveData : IPersistentData { #region Singleton protected static SaveData Instance => instance ?? (instance = new SaveData(Path.Combine(Application.persistentDataPath, "save.dat"))); private static SaveData instance = null; #endregion //Singleton #region File IO protected static string FilePath = null; protected SaveData(string filePath) : base() { FilePath = filePath; } /// <summary> /// データを読み込む /// </summary> /// <typeparam name="SaveData">セーブデータ</typeparam> /// <returns>読み込んだデータ</returns> public static UniTask<SaveData> LoadAsync() => Instance.LoadAsync<SaveData>(FilePath); /// <summary> /// データを書き込む /// </summary> /// <typeparam name="SaveData">セーブデータ</typeparam> /// <returns>書き込みが成功した場合は true, それ以外は false</returns> public UniTask<bool> SaveAsync() { this.Timestamp = DateTimeOffset.Now; return this.SaveAsync<SaveData>(FilePath); } #endregion //File IO } }
この `SaveData
のファイル読み書きを試すために下記のテストクラスを用意
using MatatabiUx.Common; using UnityEngine; public class Test : MonoBehaviour { public void Awake() { // シリアライザの初期設定 MessagePack.Resolvers.StaticCompositeResolver.Instance.Register( MessagePack.Resolvers.GeneratedResolver.Instance, // コード生成した型解決クラス MessagePack.Unity.UnityResolver.Instance, MessagePack.Unity.Extension.UnityBlitWithPrimitiveArrayResolver.Instance, MessagePack.Resolvers.StandardResolver.Instance ); var option = MessagePack.MessagePackSerializerOptions.Standard .WithCompression(MessagePack.MessagePackCompression.Lz4BlockArray) // LZ4 圧縮利用 .WithResolver(MessagePack.Resolvers.StaticCompositeResolver.Instance); MessagePack.MessagePackSerializer.DefaultOptions = option; } public async void Start() { // ファイルから読み込み var data = await SaveData.LoadAsync(); UnityEngine.Debug.Log( $"Id={data.Id}, Timestamp={data.Timestamp}"); // ファイルに書き込み await data.SaveAsync(); } }
とりあえず2回動かしてみてログを確認
最初はデフォルト値で2回目はちゃんと保存日時が書きこまれているので大丈夫そう