何时使用context.filesDir与设备保护存储路径?兼谈文件找不到崩溃排查
问题分析与解决方案
问题背景
应用出现多起崩溃,抛出异常:Fatal Exception: java.io.FileNotFoundException /data/user/0/<package-id>/files/folder_name/file_name.jpg : open failed: ENOENT (No such file or directory)
调试过程发现
- 应用通过
val file = File("${context.filesDir}/$folderName")创建File对象; - 访问路径前已调用
mkdirs(); - 日志出现
user_de相关路径记录:Successfully queried cache dir: /data/user_de/0/<package_id>/code_cacheSetting cache dir: /data/user_de/0/<package_id>/code_cache - 确认
user_de路径关联context.createDeviceProtectedStorageContext().filesDir,但此前仅用context.filesDir时运行正常。
补充信息
- 仅部分设备(如SM-G398FN、SM-G525F)出现异常,同机型也存在正常运行情况;
- 触发异常的CameraX拍照代码:
private fun takePhoto() { val imageCapture = imageCapture ?: return val imagesFolderFile = File( context.filesDir, "$folderName${File.separator}$imagesFolderName" ) val photoFile = File( imagesFolderFile, "Images/image_timestamp.jpg" ) photoFile.mkdirs() val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build() imageCapture.takePicture( outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { override fun onError(exc: ImageCaptureException) { // 异常从此处抛出 Log.e(imageCaptureLogs, exc.message.toString()) exc.printStackTrace() } override fun onImageSaved(output: ImageCapture.OutputFileResults) { } } }
关键遗漏点
1. mkdirs()调用对象错误
你给文件路径调用了mkdirs()——photoFile是要保存的jpg文件,调用mkdirs()会创建一个名为image_timestamp.jpg的目录,而非文件。CameraX试图往目录里写入图片数据,自然会触发文件找不到的异常。
正确做法是创建文件的父目录,而非文件本身:
val photoFile = File(imagesFolderFile, "Images/image_timestamp.jpg") // 创建父目录(如果不存在) photoFile.parentFile?.mkdirs() // 无需手动创建文件,CameraX会自动生成文件并写入
2. 设备保护存储的上下文混用
日志中的user_de路径来自设备保护存储,部分设备在特定场景下(比如锁屏状态下启动后台任务、开启直接启动功能),应用上下文会被自动切换为设备保护存储上下文,此时context.filesDir指向/data/user_de/0/<package-id>/files。如果代码中混用了普通上下文和设备保护存储上下文,会导致目录创建与文件写入的路径不一致,最终找不到文件。
解决方式:
- 所有文件操作统一使用同一个上下文,不要混用普通上下文和
createDeviceProtectedStorageContext()返回的上下文; - 若必须使用设备保护存储,全程使用该上下文进行文件读写;
- 检查第三方库或系统逻辑是否自动切换了上下文。
3. 路径拼接的不规范
手动拼接路径存在出错风险,建议用File构造器嵌套创建目录,更安全可靠:
// 替代手动拼接的目录创建方式 val imagesFolderFile = File(File(context.filesDir, folderName), imagesFolderName)
4. 缺少目录创建结果校验
部分设备可能因权限变化、存储状态异常导致目录创建失败,建议添加校验逻辑,提前处理错误:
val parentDir = photoFile.parentFile if (parentDir != null) { if (!parentDir.exists()) { val isCreated = parentDir.mkdirs() if (!isCreated) { Log.e("StorageError", "Failed to create directory: ${parentDir.path}") return // 提前终止,避免后续拍照失败 } } }
内容的提问来源于stack exchange,提问作者Sanket Bhangale
相关产品推荐
相关产品推荐

