为什么File(uri.path)正常运行,uri.toFile()却报Uri lacks 'file' scheme错误
报错原因分析
你遇到的报错信息如下:
java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://***.provider/files/06082021_113127.jpg
核心原因
Uri.toFile()是Android Kotlin核心库(core-ktx)提供的扩展方法,仅支持scheme为file的Uri转换,源码逻辑就是先判断Uri的scheme值是否等于file,不匹配直接抛出你遇到的上述异常。- 你代码中调用
FileProvider.getUriForFile()生成的Uri是content类型的scheme,这是Android系统为了文件共享安全设计的代理路径,不是本地文件的真实存储路径,自然不满足toFile()的调用要求。
隐藏问题说明
你代码中val test = uri?.path?.let { File(it) }的写法也是错误的:
content类型Uri的path字段返回的是ContentProvider的路径映射值,不是本地文件的真实路径,此时生成的File对象只是个空壳,无法正常读取到文件内容,只是因为路径最后一段恰好和文件名一致,所以打印name看起来正常,实际操作该文件会触发找不到文件的异常。
解决方案
分两种场景处理:
- 当前场景(自己生成的FileProvider Uri)
你在生成Uri的时候已经持有了原始的本地File对象,直接把这个File存为全局变量即可,拍照成功后直接使用该File,不需要通过Uri转换,修改后代码参考:
private var uri: Uri? = null // 新增全局变量保存原始File private var captureImageFile: File? = null binding.camera.setOnClickListener { val name = LocalDateTime.now().generateFileName() val file = File(requireContext().filesDir, "$name.jpg") // 保存File captureImageFile = file uri = FileProvider.getUriForFile( requireContext(), requireContext().packageName + ".provider", file ) takePicture.launch(uri) } private val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { success: Boolean -> if (success) { // 直接使用保存的captureImageFile即可 Log.e("image", "${captureImageFile?.name}") } }
- 通用场景(拿到第三方提供的content Uri要转File)
如果是其他应用分享/返回的content Uri,需要通过ContentResolver读取输入流,拷贝到自己应用可访问的目录下生成新的File:
fun uriToFile(context: Context, uri: Uri, targetFile: File): File? { return runCatching { context.contentResolver.openInputStream(uri)?.use { input -> targetFile.outputStream().use { output -> input.copyTo(output) } } targetFile }.getOrNull() } // 调用示例 val targetFile = File(context.cacheDir, "temp_image.jpg") val convertedFile = uriToFile(context, contentUri, targetFile)
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

