【Unity】HoloLens2の内部ストレージにアプリ内からデータを書き込む方法

HoloLens2を使った実験などで，Unityで作成したアプリケーション内から情報をHoloLens2内部に記録する際に使うコードの例です．

以前は内部ストレージに書き込む方法があることを知らずにわざわざPhotonで別のUnityプロジェクトとオブジェクト同期して記録するというかなり手間のかかることをしていましたが，いい感じにHoloLens2一台で完結できるようになったので残しておきます．

以下は，転がるボールオブジェクト「PingPongBall」の座標(x,z)を取得しテキストファイルに毎フレーム記録するスクリプトです．


```C#:InternalSaver.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO; //ファイルに書き込むために必要
using System; //ConvertとDeteTimeを使うために必要
using System.Text; //文字コードを指定するために必要

public class InternalSaver : MonoBehaviour
{
    StreamWriter sw; //x座標記録用
    StreamWriter sw2; //z座標記録用
    public GameObject pingpongBall; //位置を記録したいオブジェクト用変数
    DateTime t2; //時刻用の変数

    void Start()
    {
        //オブジェクト名でオブジェクトを取得(処理が重いらしいからtagとかで探すようにしたほうがいいかもしれない)
        pingpongBall = GameObject.Find("PingPongBall");

        //時間を取得
        t2 = DateTime.Now;

        //csvのとき
        //string file = Application.persistentDataPath + "/BallPos_x.csv";
        //string file2 = Application.persistentDataPath + "/BallPos_z.csv";

        //txtのとき
        string file = Application.persistentDataPath + "/BallPos_x.txt";
        string file2 = Application.persistentDataPath + "/BallPos_z.txt";

        if (!File.Exists(file))
        {
            Debug.Log("ファイルを作成します");
            sw = File.CreateText(file);
            sw.Flush();
            sw.Dispose();
        }
        else
        {
            Debug.Log("The file already exists.ファイルは既に存在しています");
        }

        if (!File.Exists(file2))
        {
            Debug.Log("ファイル2を作成します");
            sw2 = File.CreateText(file2);
            sw2.Flush();
            sw2.Dispose();
        }
        else
        {
            Debug.Log("The file2 already exists.ファイル2は既に存在しています");
        }

        //UTF-8で生成...2番目の引数はtrueで末尾に追記，falseでファイルごと上書き．
        sw = new StreamWriter(file, true, Encoding.UTF8);
        sw2 = new StreamWriter(file2, true, Encoding.UTF8);

        //改行
        sw.WriteLine();
        sw2.WriteLine();

        //時刻書き込み
        sw.WriteLine(Convert.ToString(t2));
        sw2.WriteLine(Convert.ToString(t2));

        //Debug.Log(t2);
    }

    void Update()
    {
        //オブジェクトのtransformを取得
        Transform ballTransform = pingpongBall.transform;

        //オブジェクトのローカル座標を取得
        Vector3 ballPos = ballTransform.localPosition;
        float x = ballPos.x;
        float y = ballPos.y;
        float z = ballPos.z;

        //Debug.Log($"{x},{z}");

        //ファイルの末尾に値を追加（Convertでfloat型の座標値をString型に変換している）
        //csvのとき
        //sw.WriteLine(Convert.ToString(x));
        //sw2.WriteLine(Convert.ToString(z));

        //txtのとき
        sw.Write(Convert.ToString(x)+",");
        sw2.Write(Convert.ToString(z)+",");

        if (pingpongBall.transform.position.y <= -0.5f)//ボール落下時の処理
        {
            //改行
            sw.WriteLine();
            sw2.WriteLine();

            //時刻t2にボールが落下したことを示すテキストを書き込む
            sw.WriteLine(Convert.ToString(t2) + "にボールが落下");
            sw2.WriteLine(Convert.ToString(t2) + "にボールが落下");
        }
        //Debug.Log(pingpongBall.transform.position.y);
    }
}
```
コメントいっぱい書いてますがわかりにくいと思うので，暇なとき追記するかもです．

ファイルの保存場所は，HoloLens2で実行したときはデバイスポータルからSystem>File explorerで，「User Folders/LocalAppData/アプリ名/LocalState」に保存されます（たぶん）．デバイスポータルかHoloLens2をPCに有線接続で取り出せると思います．

Unity上で実行したときはPCの「ユーザ名/AppData/LocalLow/DefaultCompany/ProductName」に保存されます．

上のは一例ですが，ほかにもボタンを押したタイミングや回数の取得，手や視線の位置の記録などにも使えそうですね．HoloLens2で実験してそのままHoloLens2上でアンケートに答えてもらう，とかもできそう．

___

【参考サイト】
[【Unity】【Hololens】ファイルをローカルストレージに読み込んだり書き込んだりしたかった](https://green-game.hatenablog.com/entry/2017/11/09/115817)
[HoloLensで始めるUWP - HoloLens上でファイルI/O可能な範囲](https://qiita.com/miyaura/items/75ec7f3d6ab0500ccf72)
[C# テキストファイル出力 StreamWriter](https://hironimo.com/prog/c-sharp/text-streamwriter/)
[StreamWriterクラスを使ってテキストファイルにデータを書き込む [C#]](https://johobase.com/streamwriter-class-writetext-csharp/)