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会被拒),可以申请所有文件访问权限:- 先在
AndroidManifest.xml中声明权限:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />- 启动时引导用户开启权限:
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) }- 修正路径判断逻辑,统一跨版本访问路径,避免不同系统版本访问不同文件夹:
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
相关产品推荐
相关产品推荐

