MRが楽しい

MRやVRについて学習したことを書き残す

HoloLens2アプリでXMLファイルの読み書きを行う

本日は HoloLens2 の技術調査枠です。
XmlSerializer クラスを使ってアプリ情報をXMLファイルに読み書きします。

XmlSerializer

オブジェクトから XML ドキュメントへのシリアル化および XML ドキュメントからオブジェクトへの逆シリアル化を実行します。
docs.microsoft.com

サンプルプロジェクト

以下のサンプルプロジェクトを作成しました。
アプリケーションの起動時間を XML ファイルに保存し、アプリを終了しても再起動時に以前の起動時間を確認できます。
f:id:bluebirdofoz:20210820223029j:plain

XmlSerializer クラスを使った XML ファイルの読み書きを行うクラスを作成しました。
・DataController.cs

using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;

// クラス名を別名でまとめて管理する
using CUSTOMTYPE = DataFormat;

public class DataController : MonoBehaviour
{
    /// <summary>
    /// 保持データ
    /// </summary>
    [SerializeField, Tooltip("保持データ")]
    private CUSTOMTYPE p_Data;

    /// <summary>
    /// 保存ファイル名
    /// </summary>
    [SerializeField, Tooltip("保存ファイル名")]
    private string p_FileName;

    /// <summary>
    /// データを読み込む
    /// </summary>
    public CUSTOMTYPE LoadData()
    {
        return XMLRead(p_FileName);
    }

    /// <summary>
    /// データを書き込む
    /// </summary>
    public void SaveData(CUSTOMTYPE a_Data)
    {
        XMLWrite(p_FileName, a_Data);
    }

    /// <summary>
    /// データ読み込み(XML)
    /// </summary>
    /// <returns>読み込み成否</returns>
    private CUSTOMTYPE XMLRead(string a_FileName)
    {
        // 読み込み成否
        bool ret = false;
        CUSTOMTYPE resultData = null;

        // オブジェクトの型を指定して Serializer オブジェクトを作成する
        System.Xml.Serialization.XmlSerializer serializer;
        serializer = new System.Xml.Serialization.XmlSerializer(typeof(CUSTOMTYPE));

        // ファイルの存在確認
        if (System.IO.File.Exists(XMLFilePath(a_FileName)) == true)
        {
            // 読み込みファイルを開く
            System.IO.StreamReader streamreader;
#if WINDOWS_UWP
            // 読み込みファイルを開く(UWPアプリではStreamReader(filepath)メソッドは使用不可)
            streamreader = new System.IO.StreamReader((System.IO.Stream)System.IO.File.OpenRead(XMLFilePath(a_FileName)));
#else
            // 読み込みファイルを開く
            streamreader = new System.IO.StreamReader(XMLFilePath(a_FileName), new System.Text.UTF8Encoding(false));
#endif

            // XMLファイルから逆シリアル化する
            resultData = (CUSTOMTYPE)serializer.Deserialize(streamreader);

#if WINDOWS_UWP
            // ファイルを閉じる(UWPアプリではClose()メソッドは使用不可)
            streamreader.Dispose();
#else
            // ファイルを閉じる
            streamreader.Close();
#endif

            // 読み込み成功
            ret = true;
        }

        return resultData;
    }

    /// <summary>
    /// データ書き込み(XML)
    /// </summary>
    private bool XMLWrite(string a_FileName, CUSTOMTYPE a_Data)
    {
        Debug.Log("XMLWrite");

        // 書き込み成否
        bool ret = false;

        // オブジェクトの型を指定して Serializer オブジェクトを作成する
        System.Xml.Serialization.XmlSerializer serializer;
        serializer = new System.Xml.Serialization.XmlSerializer(typeof(CUSTOMTYPE));

        // ディレクトリの存在確認
        if (System.IO.Directory.Exists(SettingFileDirectoryPath()) == true)
        {
            // 書き込みファイルを開く
            System.IO.StreamWriter streamwriter;
#if WINDOWS_UWP
            // 書き込みファイルを開く(UWPアプリではStreamWriter(filepath)メソッドは使用不可)
            streamwriter = new System.IO.StreamWriter((System.IO.Stream)System.IO.File.OpenWrite(XMLFilePath(a_FileName)));
#else
            // 書き込みファイルを開く
            streamwriter = new System.IO.StreamWriter(XMLFilePath(a_FileName), false, new System.Text.UTF8Encoding(false));
#endif

            // シリアル化してXMLファイルに保存する
            serializer.Serialize(streamwriter, a_Data);

#if WINDOWS_UWP
            // ファイルを閉じる(UWPアプリではClose()メソッドは使用不可)
            streamwriter.Dispose();
#else
            // ファイルを閉じる
            streamwriter.Close();
#endif

            // 書き込み成功
            ret = true;
        }
        return ret;
    }

    /// <summary>
    /// データ保存ディレクトリパス
    /// 実行環境によって参照ディレクトリを変更する
    /// </summary>
    private string SettingFileDirectoryPath()
    {
        string directorypath = "";
#if WINDOWS_UWP
        // HoloLens上での動作の場合、LocalAppData/AppName/LocalStateフォルダを参照する
        directorypath = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
#else
        // Unity上での動作の場合、Assets/StreamingAssetsフォルダを参照する
        directorypath = UnityEngine.Application.streamingAssetsPath;
#endif
        return directorypath;
    }

    /// <summary>
    /// アプリ設定ファイルパス(XML)
    /// 実行環境によって参照ディレクトリを変更する
    /// </summary>
    private string XMLFilePath(string a_FileName)
    {
        string filepath = "";
        filepath = System.IO.Path.Combine(SettingFileDirectoryPath(), a_FileName);
        return filepath;
    }
}

今回はデータの定義として以下のクラスを定義しています。
・DataFormat.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/// <summary>
/// 保存データフォーマット
/// </summary>
[Serializable]
public class DataFormat
{
    public List<TimeData> MarkDataList;
}

/// <summary>
/// 記録時刻
/// </summary>
[Serializable]
public class TimeData
{
    /// <summary>
    /// ID
    /// </summary>
    public string IdText;

    /// <summary>
    /// タイムスタンプ
    /// </summary>
    public DateTime DateTimeStamp;
}

この XML ファイルへの読み書きを利用して、以下のスクリプトで起動時刻の保存、テキストへの表示を行います。
・LaunchTimeRecorder.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class LaunchTimeRecorder : MonoBehaviour
{
    /// <summary>
    /// テキスト表示UI
    /// </summary>
    [SerializeField, Tooltip("テキスト表示UI")]
    private Text p_MessageText;

    /// <summary>
    /// 保存データ参照
    /// </summary>
    [SerializeField, Tooltip("保存データ参照")]
    private DataController p_DataController;

    // Start is called before the first frame update
    void Start()
    {
        // 履歴データを読み込む
        DataFormat historyData = p_DataController.LoadData();

        if (historyData == null)
        {
            historyData = new DataFormat();
            historyData.MarkDataList = new List<TimeData>();
        }

        // 起動時刻を記録する
        TimeData launchData = new TimeData();
        launchData.IdText = "Launch_" + historyData.MarkDataList.Count.ToString();
        launchData.DateTimeStamp = DateTime.Now;
        historyData.MarkDataList.Add(launchData);

        // UIにデータを表示する
        string message = "";
        foreach(TimeData timeData in historyData.MarkDataList)
        {
            message += timeData.IdText + " : " + timeData.DateTimeStamp.ToString() + Environment.NewLine;
        }
        p_MessageText.text = message;

        // 履歴データを書き込む
        p_DataController.SaveData(historyData);
    }
}

これらのスクリプトを以下の通り、シーンに設定しました。
f:id:bluebirdofoz:20210820223153j:plain

Unityエディター上での動作確認

Unityエディター上で[再生]ボタンを押してシーンを再生してみます。
XML ファイルは Assets/StreamingAssets フォルダ配下に保存され、[再生]を行う度に起動時間が保存されていきます。
f:id:bluebirdofoz:20210820223201j:plain

HoloLens2上での動作確認

HoloLens2 にアプリをデプロイして動作を確認してみます。
こちらでもアプリケーションを起動するたびに起動時間が保存され、パネルUIに表示されます。
f:id:bluebirdofoz:20210820223212j:plain

HoloLens2 上の動作では XML ファイルはアプリケーションフォルダの LocalState に保存されます。
f:id:bluebirdofoz:20210820223221j:plain

参考ページ

本記事は以下の記事の内容を HoloLens2 で改めて動作確認を行い、再編した記事です。
bluebirdofoz.hatenablog.com
bluebirdofoz.hatenablog.com