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)及以上系统要求运行时动态申请权限,静态声明仅为权限申请的前提,用户未授权时依然无法读写外部存储。
修复步骤:
- 在代码中添加权限申请逻辑:
void Awake() { // 检查并申请外部存储写权限 if (!Permission.HasUserAuthorizedPermission(Permission.ExternalStorageWrite)) { Permission.RequestUserPermission(Permission.ExternalStorageWrite); } }
- 打开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+,可二选一适配:
- 使用MediaStore API写入公共目录(支持CSV文件);
- 在Manifest的application标签中添加兼容配置,暂时沿用旧存储方式:
<application android:requestLegacyExternalStorage="true"> <!-- 你的Activity配置 --> </application>
五、测试验证方法
- 用Unity的
adb logcat查看安卓日志,搜索IOException关键字,定位具体写入失败原因; - 写入后打印文件路径,用adb命令验证文件是否存在:
Debug.Log($"文件保存路径:{filename}");
执行adb shell ls 打印的路径查看文件是否生成。
内容的提问来源于stack exchange,提问作者P D
相关产品推荐
相关产品推荐

