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

Android调用ExifInterface读取图片EXIF旋转信息报FileNotFoundException

异常原因
  • 你获取到的selectedImage是MediaStore返回的content://类型内容Uri,直接调用selectedImage.path得到的是Uri的内部路径片段(也就是报错里的/external/images/media/12729),这不是设备文件系统上的真实物理文件路径,直接把这个字符串传给ExifInterface当作本地文件路径读取,自然会触发文件找不到的异常。
  • Android 10及以上版本启用了分区存储机制,就算你通过额外逻辑拿到了图片的真实文件路径,没有对应存储权限的情况下依然无法直接通过文件路径读取,这种直接访问文件绝对路径的实现方式本身已经不兼容新版本系统。
修复方案

核心逻辑是不要依赖Uri的path字段做文件访问,通过ContentResolver打开Uri对应的输入流,再用输入流初始化ExifInterface,这个方案全Android版本兼容,不需要额外申请存储权限,也不需要额外查询图片真实路径。

  1. 修改rotateImageIfRequired方法,增加Context参数,替换ExifInterface的初始化逻辑,修改后代码如下:
private fun rotateImageIfRequired(context: Context, img: Bitmap, selectedImage: Uri): Bitmap {
    // 打开Uri对应的输入流,use函数会自动关闭流避免资源泄漏
    val exif = context.contentResolver.openInputStream(selectedImage)?.use { stream ->
        ExifInterface(stream)
    }
    return when (exif?.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
        ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(img, 90)
        ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(img, 180)
        ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(img, 270)
        else -> img
    }
}
  1. 调用该方法时传入上下文参数即可,比如在Activity中调用时直接传入this:
// 调用示例
val rotatedBitmap = rotateImageIfRequired(this, sourceBitmap, selectedImageUri)
  1. 原有的getImagepath方法返回的Content Uri本身是合法可用的,不需要修改。

补充注意:所有针对Content Uri的文件操作都不要直接使用.path字段,读写操作都应该通过ContentResolver打开流完成,才能兼容分区存储的权限规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:24:23