向有效文件写入数据时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来获取文件路径:
- 在Activity中添加全局变量保存临时文件实例:
private var imgFile: File? = null
- 修改
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!!) }
- 修改相机回调,直接使用保存的
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"}") // 此处可继续执行文件上传等后续操作 } } } }
额外注意事项
- 切勿依赖
FileProviderUri的path属性获取真实文件路径,不同系统版本或配置下该路径可能不指向实际文件。 - 本次使用的是应用私有目录
filesDir,无需申请外部存储读写权限,若切换到外部存储需额外处理权限。
内容的提问来源于stack exchange,提问作者GPorubanTKK
相关产品推荐
相关产品推荐

