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

Android Q及以上版本File.exists()始终返回false该如何解决

问题原因

Android Q(API 29)及以上版本默认启用分区存储特性,应用对外部共享存储的访问被限制,无法直接通过原始文件路径的File API判断文件是否存在,只有应用专属目录(内部存储data/data/包名/、外部存储Android/data/包名/下的路径)可以正常用File API访问。如果你的代码中PATH_SUFFIX指向的是共享存储区域,就会出现文件存在也始终返回false的问题。
如果你的文件确实存放在应用内部专属目录下,还要检查路径拼接逻辑是否存在错误:比如PATH_SUFFIX开头没有添加路径分隔符/,导致拼接出来的完整路径和实际文件路径不一致。

解决方案
  • 方案1:文件存放在应用专属目录时,使用官方API获取根路径,避免硬编码拼接错误
private fun isFileExists(): Boolean {
    var checked = false
    try {
        // 内部存储应用专属目录根路径,等价于applicationInfo.dataDir
        val rootPath = filesDir.absolutePath
        // 拼接路径时主动添加分隔符,避免拼写错误
        val filePath = "$rootPath${File.separator}$PATH_SUFFIX${File.separator}$FILE_NAME"
        val file = File(filePath)
        checked = file.exists()
    } catch (ignored: Exception) {
    }
    return checked
}
  • 方案2:文件存放在公共共享存储区域(比如DCIM、Download、Documents等公共目录)时,改用MediaStore查询判断
private fun isPublicFileExists(fileName: String): Boolean {
    // 要查询的字段,只需要查ID判断是否存在即可
    val projection = arrayOf(MediaStore.Files.FileColumns._ID)
    // 查询条件:匹配文件名
    val selection = "${MediaStore.Files.FileColumns.DISPLAY_NAME} = ?"
    val selectionArgs = arrayOf(fileName)
    //  查询所有外部存储的文件
    contentResolver.query(
        MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL),
        projection,
        selection,
        selectionArgs,
        null
    )?.use { cursor ->
        // 游标数量大于0说明存在匹配文件
        return cursor.count > 0
    }
    return false
}

如果是特定类型的文件,可以替换查询的Uri提升查询效率:比如图片用MediaStore.Images.Media.EXTERNAL_CONTENT_URI,视频用MediaStore.Video.Media.EXTERNAL_CONTENT_URI。

  • 方案3:临时兼容方案(不推荐,Android 13及以上版本不再生效)
    在AndroidManifest.xml的application节点添加android:requestLegacyExternalStorage="true"属性,请求使用旧版存储权限,即可继续使用原有File API逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 00:42:03