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

React Native选择外部目录并读取内容报错问题求助

解决RNFS读取DocumentPicker返回目录URI时的「Folder does not exist」报错

问题根源

react-native-document-picker返回的content://格式URI是Android**存储访问框架(SAF)**提供的内容URI,并非传统的文件系统路径。而react-native-fs(RNFS)的readDir方法仅支持解析真实的文件系统路径(如/storage/emulated/0/Download/IRCTC ERS),直接传入content URI自然会提示目录不存在。

解决方案

根据Android版本和需求,可选择以下方案:

方案1:将Content URI转换为真实文件路径(Android 10及以下优先)

使用第三方库将content URI转换为文件系统路径,推荐react-native-get-real-path:

  1. 安装依赖
npm install react-native-get-real-path --save
# 或 yarn add react-native-get-real-path
  1. 修改代码实现转换
import PermissionsAndroid from 'react-native/Libraries/PermissionsAndroid';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';
import RealPath from 'react-native-get-real-path';

const readSelectedDirectory = async () => {
  // 请求存储权限
  const per = await PermissionsAndroid.request(
    PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE
  );
  if (per !== PermissionsAndroid.RESULTS.GRANTED) return;

  // 选择目录
  const res = await DocumentPicker.pickDirectory();
  // 转换content URI为真实路径
  const realFilePath = await RealPath.getRealPathFromURI(res.uri);
  // 读取目录
  const files = await RNFS.readDir(realFilePath);
  console.log('目录文件列表:', files);
};

注意:Android 11及以上因Scoped Storage限制,部分目录无法获取真实路径,此方案可能失效。

方案2:通过Android原生API直接遍历Content URI对应的目录(全版本兼容)

由于RNFS不支持SAF的content URI,可编写原生模块调用Android的DocumentFile API遍历目录:

  1. 创建Android原生模块(示例核心代码)
import android.content.Context;
import android.net.Uri;
import androidx.documentfile.provider.DocumentFile;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import org.json.JSONArray;
import org.json.JSONObject;

public class SAFDirectoryReaderModule extends ReactContextBaseJavaModule {
    private final ReactApplicationContext reactContext;

    public SAFDirectoryReaderModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Override
    public String getName() {
        return "SAFDirectoryReader";
    }

    @ReactMethod
    public void listFiles(String treeUri, Promise promise) {
        try {
            Uri uri = Uri.parse(treeUri);
            DocumentFile directory = DocumentFile.fromTreeUri(reactContext, uri);
            JSONArray fileArray = new JSONArray();

            if (directory != null && directory.isDirectory()) {
                for (DocumentFile file : directory.listFiles()) {
                    JSONObject fileObj = new JSONObject();
                    fileObj.put("name", file.getName());
                    fileObj.put("uri", file.getUri().toString());
                    fileObj.put("isDirectory", file.isDirectory());
                    fileArray.put(fileObj);
                }
            }
            promise.resolve(fileArray.toString());
        } catch (Exception e) {
            promise.reject("SAF_ERROR", e.getMessage());
        }
    }
}
  1. 在RN端调用原生模块
import { NativeModules } from 'react-native';
const { SAFDirectoryReader } = NativeModules;

// 选择目录后调用
const res = await DocumentPicker.pickDirectory();
const fileListStr = await SAFDirectoryReader.listFiles(res.uri);
const fileList = JSON.parse(fileListStr);
console.log('目录文件列表:', fileList);

方案3:改用支持SAF的文件操作库

替换RNFS为支持content URI的库,例如react-native-document-file-picker,该库可直接处理SAF的目录URI,无需额外转换。

额外注意事项

  • Android 11+:若需访问所有外部存储,需申请MANAGE_EXTERNAL_STORAGE权限,但该权限需用户手动在系统设置中开启,且Google Play对其使用有严格限制,仅特定场景允许。
  • 权限配置:确保AndroidManifest.xml中已添加android:requestLegacyExternalStorage="true"(仅Android 10有效),并正确声明存储权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 10:55:04