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

Android实现将文件写入用户选择的外置存储卡指定路径问题

你当前实现的核心问题是:通过ACTION_OPEN_DOCUMENT_TREE拿到的是存储访问框架(SAF)的树形Uri,你把它转换为本地文件路径后用File类操作,在外置存储卡场景下完全行不通:从Android 4.4开始,应用没有外置存储卡的直接文件读写权限,Android 10+分区存储规则更是彻底禁止了第三方应用直接访问外置存储卡的公共路径,哪怕路径正确也会抛出权限异常。

以下是可用的修复方案:

第一步:持久化Uri授权

用户选择目录后,系统给的Uri授权是临时的,重启应用就会失效,你需要先手动持久化读写权限,代码加在onActivityResult最开头:

Uri treeUri = data.getData();
// 持久化读写权限
final int takeFlags = data.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(treeUri, takeFlags);

第二步:用DocumentFile API操作文件(替代原File操作逻辑)

SAF官方提供的DocumentFile类适配所有SAF返回的路径,不管是内部存储还是外置存储卡都可以正常读写,不需要转本地路径:

// 从选择的树形Uri创建DocumentFile实例
DocumentFile rootDir = DocumentFile.fromTreeUri(this, treeUri);
if (rootDir == null || !rootDir.exists()) {
    Log.e("ALERT", "所选目录无效");
    return;
}
// 创建目标文件,第二个参数是MIME类型,文本文件填text/plain即可
DocumentFile targetFile = rootDir.findFile(fileName);
if (targetFile == null) {
    targetFile = rootDir.createFile("text/plain", fileName);
}
if (targetFile == null) {
    Log.e("ALERT", "文件创建失败");
    return;
}

第三步:写入文本内容示例

拿到文件的Uri之后,直接开输出流写内容即可:

try {
    OutputStream outputStream = getContentResolver().openOutputStream(targetFile.getUri());
    outputStream.write("你要写入的文本内容".getBytes(StandardCharsets.UTF_8));
    outputStream.close();
} catch (IOException e) {
    e.printStackTrace();
    Log.e("ALERT", "文件写入失败:" + e.getMessage());
}

额外说明

  • 你原来的FileUtil工具类可以完全不用了,SAF场景下不需要转本地文件路径,适配所有Android 5.0+系统,包括安卓11、12、13、14等高版本。
  • 不需要额外申请存储权限,SAF的权限是用户主动选择目录时授予的,符合Google Play的权限规则要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 07:18:03