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

何时使用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_cache
    Setting 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 18:19:59