Android Q写入getExternalFilesDir()子目录触发ENOENT错误原因咨询
问题原因分析与解决方案
先帮你拆解清楚这个问题的来龙去脉:
1. 先搞懂getExternalFilesDir(null)的特性
在Android Q及以上版本中,context.getExternalFilesDir(null)返回的路径是/storage/emulated/0/Android/data/[你的包名]/files——这个目录是系统为你的应用自动创建的专属存储目录,应用拥有完整读写权限,不需要额外申请存储权限,也不存在访问限制。
2. 为什么加包名子目录会触发ENOENT错误?
你之前的代码在这个已存在的目录下拼接了包名,得到路径/storage/emulated/0/Android/data/com.mp.test/files/com.mp.test,问题就出在这个com.mp.test子目录上:
- 这个子目录并没有被提前创建;
- 看你的资产复制代码,只有当遍历到的资产是目录类型时,才会调用
outDir.mkdirs()创建对应子目录; - 但从日志来看,第一个要处理的资产是
0.key(文件类型),此时com.mp.test父目录还不存在,直接尝试创建0.key文件时,系统找不到父目录,就抛出了ENOENT (No such file or directory)错误。
说白了就是:要写的文件的父目录不存在,又没提前创建,自然写不了文件。
3. 两种解决方案
方案一:主动创建子目录再返回路径
如果确实需要这个包名子目录,在返回路径前先主动创建它:
public String getAppAssetsExtractingPath() { Context context = _activity.getApplicationContext(); File externalFilesDir = context.getExternalFilesDir(null); // 创建包名子目录 File targetDir = new File(externalFilesDir, _activity.getPackageName()); if (!targetDir.exists()) { // mkdirs会递归创建所有不存在的父目录 targetDir.mkdirs(); } return targetDir.getAbsolutePath(); }
方案二:直接用系统提供的专属目录
其实getExternalFilesDir(null)返回的目录本身就是和你的包名绑定的专属目录,完全不需要再额外嵌套一层包名子目录。直接用这个路径,既不会有目录不存在的问题,也符合Android Q的存储规范:
public String getAppAssetsExtractingPath() { return _activity.getApplicationContext().getExternalFilesDir(null).getAbsolutePath(); }
这样你的资产复制代码就能正常运行,不会再触发ENOENT错误了。
内容的提问来源于stack exchange,提问作者VMS




