Android FileInputStream取正确URI仍抛FileNotFoundException异常排查
报错原因
java.io.FileNotFoundException: ... ENOENT (No such file or directory) 报错的核心原因是你对ACTION_OPEN_DOCUMENT返回的Uri使用方式完全错误:
- 这个接口返回的是Content Provider类型的Uri(格式为
content://...),不是指向本地文件系统路径的File Uri。你调用uri.getPath()拿到的/document/document:277030只是ContentProvider内部的资源标识段,根本不是磁盘上真实存在的文件路径,用这个字符串构造File对象去读,系统必然找不到对应文件。 - 你配置的
android:requestLegacyExternalStorage="true"和READ_EXTERNAL_STORAGE权限解决不了这个问题:前者仅在Android 10系统上临时生效,Android 11及以上版本会直接忽略该配置;后者是访问公共存储目录文件需要的权限,而SAF(存储访问框架)返回的Uri是通过临时授权机制给你访问权限的,本身不需要申请全局存储权限,和你有没有加这个权限无关。
修复方案
不要尝试把SAF返回的Content Uri硬转成File对象访问,直接通过系统提供的ContentResolver打开输入流即可,这是全Android版本兼容的标准写法:
InputStream fileInputStream = null; try { // 直接通过ContentResolver打开Uri对应的文件输入流 fileInputStream = getContentResolver().openInputStream(uri); // 此处写你的输入流读取、处理逻辑即可 } catch (FileNotFoundException e) { e.printStackTrace(); } finally { // 流使用完成后必须关闭,避免内存泄漏 if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
特殊场景处理
如果你的业务逻辑必须拿到File对象(比如对接强制要求传File参数的第三方SDK),不要硬解析Uri路径,先通过上面的输入流把文件拷贝到应用自身的私有目录,再操作拷贝后的文件:
File cacheFile = new File(getCacheDir(), "selected_file.tmp"); try (InputStream is = getContentResolver().openInputStream(uri); FileOutputStream os = new FileOutputStream(cacheFile)) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } catch (IOException e) { e.printStackTrace(); } // 后续直接操作cacheFile这个File对象即可,该文件在你应用私有目录下,不需要额外权限
注意:不要使用网上流传的各种硬解析Content Uri真实路径的工具类,不同Android版本、不同厂商的系统返回的Uri格式没有统一规则,硬解析路径会在大量机型上出现兼容性问题,官方从来没有提供过从Content Uri获取真实文件路径的公开API。
内容的提问来源于stack exchange,提问作者user19152825
相关产品推荐
相关产品推荐

