You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HoloLens2部署Unity应用时CsvHelper保存CSV的路径获取方案

HoloLens2端CsvHelper写入CSV文件的路径适配方案

问题背景

  • 开发环境为Unity,目标平台HoloLens2,需求是使用CsvHelper生成存储手部运动检测数据的CSV文件,文件名自动按采集手类型(左手/右手)、写入时间拼接生成
  • 编辑器下远程调试时,硬编码本地PC磁盘路径的写入逻辑可正常运行;将应用部署到HoloLens2设备端后,硬编码的PC路径完全失效
  • 由于文件为程序自动命名、且CsvHelper写入逻辑需要直接传入可写路径/流,无法每次写入都通过文件选择器交互指定路径,此前未找到HoloLens2端可直接使用的路径规则

初始版本硬编码PC路径的代码如下:

/// <summary>
/// Method <c>WriteInCsv</c> writes the records in a .csv file. Files are named by corresponding hand, and the dateTime of writing.
/// </summary>
/// <param name="records">List of all the saved data</param>
/// <param name="hand">Which hand has the data been recorded from : 0 for right hand, 1 for left hand. </param>
public void WriteInCsv(List<CoordCSV> records, int hand=0)
{
    if (records.Count > 0)
    {
        string path = "C:\\Users\\AT04760\\Documents\\2022_HOLOLENS\\CSV Export\\test2_"; //硬编码的PC本地路径,设备端不可用
        string dateTime = System.DateTime.Now.Day + "-" + System.DateTime.Now.Month + "_" + System.DateTime.Now.Hour + "-" + System.DateTime.Now.Minute + "-" + System.DateTime.Now.Second;
        if (hand == 1)
        {
            path += "LeftHand_" + dateTime + ".csv";
        }
        else
        {
            path += "RightHand_" + dateTime + ".csv";
        }
        using (var writer = new StreamWriter(path))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            csv.Context.RegisterClassMap<CoordMap>();
            csv.WriteRecords(records);
        }
    }
}

可运行适配方案

核心逻辑:HoloLens2跑的是UWP系统,不支持像PC那样直接硬编码盘符路径,得用UWP原生的Windows.Storage接口拿合法可写目录:第一次运行弹个文件夹选择器让用户选一次存数据的地方,把目录访问权限存在FutureAccessList里缓存住,之后再运行不用重复选,直接拿到目录的可写流就能按自动生成的文件名写入,完全兼容原来用的StreamWriter和CsvHelper。

适配后的可运行代码如下:

public void WriteInCsv(List<CoordCSV> records, string folderName, int hand=0)
{
    if (records.Count > 0)
    {
        string fileName = "test_";
        string dateTime = System.DateTime.Now.Day + "-" + System.DateTime.Now.Month + "_" + System.DateTime.Now.Hour + "-" + System.DateTime.Now.Minute + "-" + System.DateTime.Now.Second;
        if (hand == 1)
        {
            fileName += "LeftHand_" + dateTime + ".csv";
        }
        else
        {
            fileName += "RightHand_" + dateTime + ".csv";
        }

        // 若要继续使用CsvHelper,无需手动拼接CSV行,拿到流后直接传入CsvWriter即可
        List<string> lines = new List<string>();
        lines.Add("Finger,TimeStamp,Position,Rotation(Quaternion)");
        foreach (CoordCSV data in records)
        {
            lines.Add(data.Finger +"," + data.Timestamp + "," + data.Position + "," + data.Rotation);
        }

#if !UNITY_EDITOR && UNITY_WSA_10_0
        // UWP存储相关API必须在UI线程调用
        UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
        {
            Windows.Storage.StorageFolder folder;
            // 检查是否已经缓存过目标目录的访问权限
            if(Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.ContainsItem(folderName)){
                folder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync(folderName);
            }
            else{
                // 无缓存权限时弹出文件夹选择器,让用户指定一次存储目录
                var folderPicker = new Windows.Storage.Pickers.FolderPicker();
                folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
                folderPicker.FileTypeFilter.Add("*");
                folder = await folderPicker.PickSingleFolderAsync();
            }
            // 切回应用线程执行写入逻辑
            UnityEngine.WSA.Application.InvokeOnAppThread(async () => 
            {
                if (folder != null)
                {
                    // 缓存目录权限,后续启动无需重复选择
                    Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.AddOrReplace(folderName, folder);
                    // 打开文件流,无需手动拼接绝对路径
                    using (StreamWriter writer = new StreamWriter(await folder.OpenStreamForWriteAsync(fileName, CreationCollisionOption.OpenIfExists)))
                    {
                        foreach(string line in lines){
                            await writer.WriteLineAsync(line);
                        }
                        // 若使用CsvHelper,替换上面的逐行写入逻辑即可:
                        // using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
                        // {
                        //     csv.Context.RegisterClassMap<CoordMap>();
                        //     csv.WriteRecords(records);
                        // }
                    }
                }
            }, false);
        }, false);
#endif
        // 编辑器下可保留原有PC路径写入逻辑,方便调试
#if UNITY_EDITOR
        string editorPath = "C:\\Users\\AT04760\\Documents\\2022_HOLOLENS\\CSV Export\\" + fileName;
        using (var writer = new StreamWriter(editorPath))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            csv.Context.RegisterClassMap<CoordMap>();
            csv.WriteRecords(records);
        }
#endif
    }
}

注意事项

  • 首次在HoloLens2端运行时,系统会弹出文件夹选择界面,选一个可访问的存储位置就行(比如图片库、本地存储里自己建的文件夹),选过一次之后后续写入不会再弹选择框
  • 别硬写HoloLens2的系统绝对路径,UWP应用有权限沙箱,直接访问未授权的路径必抛权限错误
  • 线程调度的代码不能省:UWP的文件选择器、存储相关API必须在UI线程调用,不然会抛线程异常

内容的提问来源于stack exchange,提问作者Sashell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:18:21