授予SD卡文件夹权限后无法写入子文件夹问题排查
Android外部SD卡子目录写入失败问题分析与解决
问题原因
核心问题是手动拼接Uri字符串的方式不符合Android存储访问框架(SAF)的规则。SAF通过DocumentFile管理文件和目录,每个目录的Uri是系统分配的唯一标识,并非简单拼接原路径字符串就能生成有效且有权限的子目录Uri,这种拼接出来的Uri既没有权限授权,也无法被系统识别为合法的SAF Uri,最终导致写入失败。
操作中的错误点
- 错误认为可以通过拼接原文件夹Uri的字符串来生成子目录Uri,完全忽略了SAF的权限机制和Uri管理逻辑
- 没有利用
DocumentFile提供的API获取已创建的子目录对象,而是自行构造无效Uri进行操作
解决代码与步骤
不要手动拼接Uri,而是通过DocumentFile的API获取子目录对象,再基于该对象完成文件写入:
1. 创建并获取子目录的DocumentFile对象
// 原选中目录的Uri字符串转Uri Uri parentTreeUri = Uri.parse(uri_string); // 获取原目录的DocumentFile对象 DocumentFile parentDir = DocumentFile.fromTreeUri(context, parentTreeUri); // 创建子文件夹(若已存在则直接返回已有对象) DocumentFile subDir = parentDir.createDirectory("new_subfolder"); // 容错处理:子目录创建失败时的逻辑 if (subDir == null) { // 这里可以添加提示用户的逻辑,比如Toast return; }
2. 写入文件到子目录
复用步骤2的下载逻辑,但替换为子目录的DocumentFile对象来创建文件:
URLConnection conexion = url_download.openConnection(); conexion.connect(); int lenghtOfFile = conexion.getContentLength(); InputStream input = new BufferedInputStream(url_download.openStream()); OutputStream output = null; // 基于子目录创建目标文件 DocumentFile newFile = subDir.createFile("application/zip", zipname); if (newFile == null) { // 文件创建失败,关闭输入流并返回 input.close(); return; } output = the_context.getContentResolver().openOutputStream(newFile.getUri()); byte data[] = new byte[1024]; long total = 0; int count; while ((count = input.read(data)) != -1) { total += count; publishProgress((int) (total * 100 / lenghtOfFile)); output.write(data, 0, count); if (isCancelled()) break; } // 收尾操作 output.flush(); output.close(); input.close();
额外注意事项
createDirectory()方法会自动处理目录已存在的情况,直接返回已有的目录对象,无需额外判断- 所有SAF相关的文件操作必须通过
DocumentFile提供的API完成,禁止手动拼接Uri字符串,否则会触发权限或格式错误 - 务必添加空值判断,避免因目录/文件创建失败导致空指针异常
内容的提问来源于stack exchange,提问作者scheininger
相关产品推荐
相关产品推荐

