Android调用ExifInterface读取图片EXIF旋转信息报FileNotFoundException
异常原因
- 你获取到的
selectedImage是MediaStore返回的content://类型内容Uri,直接调用selectedImage.path得到的是Uri的内部路径片段(也就是报错里的/external/images/media/12729),这不是设备文件系统上的真实物理文件路径,直接把这个字符串传给ExifInterface当作本地文件路径读取,自然会触发文件找不到的异常。 - Android 10及以上版本启用了分区存储机制,就算你通过额外逻辑拿到了图片的真实文件路径,没有对应存储权限的情况下依然无法直接通过文件路径读取,这种直接访问文件绝对路径的实现方式本身已经不兼容新版本系统。
修复方案
核心逻辑是不要依赖Uri的path字段做文件访问,通过ContentResolver打开Uri对应的输入流,再用输入流初始化ExifInterface,这个方案全Android版本兼容,不需要额外申请存储权限,也不需要额外查询图片真实路径。
- 修改
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 } }
- 调用该方法时传入上下文参数即可,比如在Activity中调用时直接传入
this:
// 调用示例 val rotatedBitmap = rotateImageIfRequired(this, sourceBitmap, selectedImageUri)
- 原有的
getImagepath方法返回的Content Uri本身是合法可用的,不需要修改。
补充注意:所有针对Content Uri的文件操作都不要直接使用
.path字段,读写操作都应该通过ContentResolver打开流完成,才能兼容分区存储的权限规则。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

