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

向有效文件写入数据时Android为何判定文件无效?

相机拍摄图片存储到临时文件后文件不存在的问题

问题描述

尝试将相机拍摄的图片存储到应用私有目录的临时文件中,用于后续网络任务。已通过FileProvider生成Uri并传入相机Activity,拍摄前日志显示文件存在,但拍摄完成后日志显示文件不存在,且两次日志中的文件名一致。已确认Uri有效、目标目录存在。

相关代码

Manifest配置

<provider
    android:authorities="${applicationId}.provider"
    android:name="androidx.core.content.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       android:resource="@xml/file_paths"/>
</provider>

file_paths.xml

<?xml version="1.0" encoding="UTF-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root" path="."/>
    <files-path name="my_images" path="images/"/>
</paths>

Activity核心代码

private fun prepURI(): Uri { //create a temporary file and return the file's Uri
    val path = File(filesDir, "my_images")
    if(!path.exists()) { path.mkdirs(); println("Path Does Not Exist!") }        
    val imgFile = File.createTempFile("IMG_",".jpg", path)
    Log.d("Camera_Log", "image ${imgFile.name} ${ if(imgFile.exists()) "exists" else "doesn't exist"}")
    return getUriForFile(this, "${this.packageName}.provider", imgFile)
}

private fun registerLauncher() { //create activityResultLauncher for camera
    launcher = registerForActivityResult(ActivityResultContracts.TakePicture()) { isSaved ->
        if (isSaved) {
            val file = File(imageUri.path!!)
            Log.d("Camera_Log", "image ${file.name} ${ if(file.exists()) "exists" else "doesn't exist"}")
        }
    } 
}

private fun handleCamera() { //check permissions and launch camera with Uri from prepURI()
    if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_CODE)
    } else launcher.launch(imageUri)
}

问题原因

核心错误在于相机回调中通过imageUri.path创建File对象:
FileProvider生成的Uri是虚拟路径(格式类似content://com.your.app.provider/my_images/IMG_xxxx.jpg),其path属性返回的是/my_images/IMG_xxxx.jpg,并非应用私有目录下的真实文件路径。直接用这个路径创建File,自然找不到实际存在的文件。

解决方案

保存创建临时文件时的File实例,而非仅依赖Uri来获取文件路径:

  1. 在Activity中添加全局变量保存临时文件实例:
private var imgFile: File? = null
  1. 修改preURI()方法,赋值保存临时文件:
private fun prepURI(): Uri {
    val path = File(filesDir, "my_images")
    if (!path.exists()) {
        path.mkdirs()
        println("Path Does Not Exist!")
    }
    imgFile = File.createTempFile("IMG_", ".jpg", path)
    Log.d("Camera_Log", "image ${imgFile!!.name} ${ if(imgFile!!.exists()) "exists" else "doesn't exist"}")
    return getUriForFile(this, "${this.packageName}.provider", imgFile!!)
}
  1. 修改相机回调,直接使用保存的File实例:
private fun registerLauncher() {
    launcher = registerForActivityResult(ActivityResultContracts.TakePicture()) { isSaved ->
        if (isSaved) {
            imgFile?.let { file ->
                Log.d("Camera_Log", "image ${file.name} ${ if(file.exists()) "exists" else "doesn't exist"}")
                // 此处可继续执行文件上传等后续操作
            }
        }
    } 
}

额外注意事项

  • 切勿依赖FileProvider Uri的path属性获取真实文件路径,不同系统版本或配置下该路径可能不指向实际文件。
  • 本次使用的是应用私有目录filesDir,无需申请外部存储读写权限,若切换到外部存储需额外处理权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 03:47:50