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

Android 11获取存储文件夹文件名报EACCES权限拒绝问题

问题根因

你的代码有两处核心问题,直接导致Android 11上读取失败:

  • 版本判断逻辑倒置,跨版本访问路径不一致
    你的分支判断逻辑是:Android 11以下(API < 30)访问外部存储根目录下的Keeper文件夹,Android 11及以上访问Documents公共目录下的Keeper文件夹。两个路径完全独立,如果你之前的文件是存在根目录的Keeper中,Android 11上访问的是另一个空文件夹,自然返回列表大小为0。
  • 未适配Android 11强制启用的分区存储规则
    Android 11开始分区存储机制强制生效,即便你申请了READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限,也无权直接通过File接口访问外部存储根目录、其他应用专属目录的文件,直接访问会抛出EACCES (Permission denied)异常。你之前在AndroidManifest里配置的requestLegacyExternalStorage=true临时兼容标记,在Android 11上已经失效。

另外你手动拼接路径写死双斜杠//属于不规范写法,虽然Linux内核会自动识别多余斜杠不会引发路径错误,但建议直接用File类的双参数构造方法拼接路径,自动适配系统分隔符。

修复方案

根据你的业务需求选对应方案即可:

方案1:文件不需要在应用卸载后留存

直接使用应用专属外部存储目录,所有Android版本都不需要申请任何存储权限,无兼容问题:

// 目录路径为 /storage/emulated/0/Android/data/你的应用包名/files/Documents/Keeper
val folder = File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "Keeper")
if (!folder.exists()) folder.mkdirs()
val files = folder.listFiles()
// 后续文件处理逻辑

该目录完全归当前应用所有,分区存储规则下无访问限制,缺点是应用卸载时目录下的所有文件会被系统清除。

方案2:文件需要存在公共目录,应用卸载后不丢失

  • 如果仅需要读写自己应用写入公共目录的文件:直接使用MediaStoreAPI读写Documents目录下的Keeper文件夹即可,Android 13+按需申请对应READ_MEDIA_*权限,不需要申请全量存储权限。
  • 如果需要管理Keeper目录下的所有文件(包括其他应用写入的文件),且应用核心功能为文件管理、数据备份类(否则上架Google Play会被拒),可以申请所有文件访问权限:
    1. 先在AndroidManifest.xml中声明权限:
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    
    1. 启动时引导用户开启权限:
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
        val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
        intent.data = Uri.parse("package:$packageName")
        startActivity(intent)
    }
    
    1. 修正路径判断逻辑,统一跨版本访问路径,避免不同系统版本访问不同文件夹:
    val targetDir = "Keeper"
    val folder = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        File(Environment.getExternalStorageDirectory(), targetDir)
    } else {
        File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), targetDir)
    }
    // 先判断文件夹存在且是目录,再读取文件列表,避免空指针
    if (folder.exists() && folder.isDirectory) {
        val files = folder.listFiles()
        // 后续文件处理逻辑
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:24:34