You need to enable JavaScript to run this app. Kotlin应用读取外部存储音频触发FileNotFoundException异常原因求解
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin应用读取外部存储音频触发FileNotFoundException异常原因求解

问题原因
  • 核心错误是混淆了Content URI和本地文件路径的概念:从系统选择Intent返回的data.data是content://开头的内容URI,并不是文件的真实存储路径,调用uri.path拿到的只是URI自身的路径片段,不是本地文件系统的有效路径,直接用该路径新建File对象必然找不到对应文件,触发FileNotFoundException。
  • 适配问题:如果应用targetSdk >= 30(Android 11及以上),即便拿到了文件真实路径,没有MANAGE_EXTERNAL_STORAGE权限的前提下,也无法直接通过File API访问公共存储的媒体文件。
  • 权限缺失:Android 6.0及以上设备如果没有动态申请对应存储读取权限,也会导致读取文件失败抛出该异常。
修复方案

你完全不需要将URI转为File对象,ContentResolver本身支持直接通过原始内容URI打开输入流,修改逻辑如下:

  1. 优先存储原始URI,不要提取path字段
// 观察ViewModel时直接保存URI,不要转路径字符串
var newAudioUri: Uri? = null
newAudioViewModel!!.getNewAudio().observe(viewLifecycleOwner, Observer<Uri?> { audio ->
    newAudioUri = audio
})
  1. 直接通过URI打开输入流构造RequestBody
newAudioUri?.let { uri ->
    context?.contentResolver?.openInputStream(uri)?.use { inputStream ->
        val requestFile = RequestBody.create(MediaType.parse("audio/mpeg"), inputStream.readBytes())
        // 后续处理requestFile的业务逻辑
    } ?: throw IOException("无法打开对应URI的输入流")
}
补充注意事项
  • 权限适配:Android 6.0-10需要动态申请READ_EXTERNAL_STORAGE权限,Android 13及以上需要动态申请READ_MEDIA_AUDIO权限。
  • 资源管理:用use方法包裹输入流操作,会在使用结束后自动关闭流,避免资源泄漏。
  • 空安全优化:尽量避免用!!强制空断言,优先使用?.、let等安全调用方式,避免空指针崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.20 11:36:04