DocumentFile:统一的文档树访问 · AndroidX 源码指南
AAndroidX 源码指南
文件与分享
文件与分享 · androidx.documentfile

DocumentFile:统一的文档树访问DocumentFile 1.1.0-rc01

fromFile、fromSingleUri 与 fromTreeUri 的职责划分与平台差异。

最后更新 2026-08-01

复制即用:打开文档树

// 请求用户选择一个目录(返回 treeUri)
private static final int OPEN_TREE_CODE = 1;

private void openDirectory() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, OPEN_TREE_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == OPEN_TREE_CODE && resultCode == RESULT_OK) {
        Uri treeUri = data.getData();
        // 持久化权限(可选)
        getContentResolver().takePersistableUriPermission(
            treeUri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        );
        DocumentFile tree = DocumentFile.fromTreeUri(this, treeUri);
        useTree(tree);
    }
}

private void useTree(DocumentFile tree) {
    // 列出文件
    for (DocumentFile child : tree.listFiles()) {
        Log.d("DocTree", child.getName() + " / " + child.getType());
    }
    // 创建文件
    DocumentFile note = tree.createFile("text/plain", "note.txt");
    // 创建目录
    DocumentFile dir = tree.createDirectory("images");
}

三种入口,三种权限来源

入口权限来源平台要求
fromFile(File)不获得额外权限(java.io.File 原有权限)
fromSingleUri(context, uri)ACTION_OPEN_DOCUMENT/ACTION_CREATE_DOCUMENT 单次授权API 19+
fromTreeUri(context, uri)ACTION_OPEN_DOCUMENT_TREE 目录授权API 21+

核心DocumentFile 只做访问,不替你获得权限——权限来自用户选择的 URI。

树内操作

DocumentFile tree = DocumentFile.fromTreeUri(context, treeUri);

tree.listFiles()            // 遍历子项
tree.createFile(mime, name) // 建文件
tree.createDirectory(name)  // 建目录
tree.findFile(name)         // 查找
file.delete()               // 删除
file.renameTo(name)         // 重命名

底层实现类(RawDocumentFileSingleDocumentFileTreeDocumentFileDocumentsContractApi19)按平台版本分发——API 24 和 API 33 调用走不同实现。

读写内容

// DocumentFile 不处理流,读写用 ContentResolver
Uri uri = file.getUri();
InputStream input = getContentResolver().openInputStream(uri);
// 或用 OutputStream 写
OutputStream output = getContentResolver().openOutputStream(uri, "w");

常见陷阱

  • 忘持久化权限:重启后 treeUri 权限丢失(用 takePersistableUriPermission)。
  • 虚拟文档isVirtual() 为 true 的可能没有直接流。
  • fromFile 无额外权限:不能访问其他应用私有目录。
  • DocumentFile 不做复制:流复制自己写。

明确不解决什么

  • 不授予权限:权限来自用户选择的 URI,DocumentFile 只做访问。
  • 不做流复制与编码转换:读写仍需 ContentResolverInputStream/OutputStream
  • 不是通用文件系统抽象:虚拟文档(isVirtual())可能没有可直接读取的流。

要点

  • 三种入口对应三种权限来源;treeUri 是目录管理的常用入口。
  • 树内 listFiles/createFile/createDirectory/findFile 递归工作。
  • 读写流走 ContentResolver;DocumentFile 只封装元数据操作。
  • 持久化权限记得 takePersistableUriPermission。

相关页面