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

Unity安卓应用无法生成CSV文件(编辑器运行正常)

Unity安卓CSV保存失败问题排查与解决

核心问题分析

编辑器正常但APK失效,通常和Android存储权限机制、文件路径正确性、变量未初始化这几个核心点相关,结合你的代码和配置,逐一拆解解决:

一、路径拼接错误:Path.Combine用法有误

你的Start方法里路径拼接逻辑存在问题:

filename = Application.dataPath + CSVFileName;
filename = Path.Combine(Application.persistentDataPath + CSVFileName);

Path.Combine的正确用法是传入多个独立路径片段,而非拼接后整体传入,错误用法会导致路径格式异常。Android上Application.persistentDataPath属于应用私有存储路径,无需额外权限即可读写;若要写入公共存储(如Download文件夹)才需要外部存储权限。

修复代码:

void Start()
{
    // 私有存储路径(无需权限,APK可直接读写)
    filename = Path.Combine(Application.persistentDataPath, CSVFileName);
    // 若需写入公共Download文件夹(需权限),替换为下方路径
    // filename = Path.Combine(AndroidOSExternalDownloadPath(), CSVFileName);
}

// 辅助方法:获取安卓公共Download文件夹路径
string AndroidOSExternalDownloadPath()
{
    return Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "Download");
}

二、缺失动态权限申请:Android 6.0+需运行时授权

仅在Manifest中声明权限是不够的,Android 6.0(API 23)及以上系统要求运行时动态申请权限,静态声明仅为权限申请的前提,用户未授权时依然无法读写外部存储。

修复步骤:

  1. 在代码中添加权限申请逻辑:
void Awake()
{
    // 检查并申请外部存储写权限
    if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite))
    {
        Permission.RequestUserPermission(Permission.ExternalStorageWrite);
    }
}
  1. 打开Unity Player Settings,在Android配置中:
    • 将Target API Level设为Automatic (highest installed)或对应目标级别;
    • 把Write Permission设置为External (SDCard)(路径:Player Settings > Android > Publishing Settings > Build > Write Permission)。

三、变量未初始化:空值引发写入异常

你的代码中value_id、value_coor_x等变量未初始化,若Dictionary中缺少对应Key,变量会保持空值,可能导致写入文件时抛出异常,甚至无法生成文件。

修复代码:

public void OnCickCSVFileSave()
{
    Dictionary<string, Dictionary<string, string>> DataList = chairDataStored;

    if (DataList.Count > 0)
    {
        // 使用using自动释放文件流,避免手动Close遗漏导致资源泄漏
        using (TextWriter tw = new StreamWriter(filename, false))
        {
            tw.WriteLine("Name,ID,Coordinate - X,Coordinate - Y,Coordinate - Z,Color,Height,Width");
        }

        using (TextWriter tw = new StreamWriter(filename, true))
        {
            foreach (var outer in DataList)
            {
                // 每次循环初始化变量,避免上一次循环的残留值
                value_id = "";
                value_coor_x = "";
                value_coor_y = "";
                value_coor_z = "";
                value_color = "";
                value_height = "";
                value_width = "";

                foreach (var inner in outer.Value)
                {
                    switch (inner.Key)
                    {
                        case "ID": value_id = inner.Value; break;
                        case "Coordinate - X": value_coor_x = inner.Value; break;
                        case "Coordinate - Y": value_coor_y = inner.Value; break;
                        case "Coordinate - Z": value_coor_z = inner.Value; break;
                        case "Color": value_color = inner.Value; break;
                        case "Height": value_height = inner.Value; break;
                        case "Width": value_width = inner.Value; break;
                    }
                }
                // 拼接行数据,空值显示为空白
                string line = $"{outer.Key},{value_id},{value_coor_x},{value_coor_y},{value_coor_z},{value_color},{value_height},{value_width}";
                tw.WriteLine(line);
                Debug.Log($"CSV写入行:{line}");
            }
        }
    }
}

四、Android 10+存储适配:Scoped Storage限制

Android 10(API 29)及以上引入了Scoped Storage机制,即使申请权限,直接读写公共目录也会受限。若Target API为29+,可二选一适配:

  1. 使用MediaStore API写入公共目录(支持CSV文件);
  2. 在Manifest的application标签中添加兼容配置,暂时沿用旧存储方式:
<application android:requestLegacyExternalStorage="true">
    <!-- 你的Activity配置 -->
</application>

五、测试验证方法

  1. 用Unity的adb logcat查看安卓日志,搜索IOException关键字,定位具体写入失败原因;
  2. 写入后打印文件路径,用adb命令验证文件是否存在:
Debug.Log($"文件保存路径:{filename}");

执行adb shell ls 打印的路径查看文件是否生成。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:55:07