使用Apache Commons IO遍历文件目录触发AccessDeniedException异常问题
异常原因
这个java.nio.file.AccessDeniedException: /storage/emulated/0/Android/data异常是Android系统权限限制导致的,和Apache Commons IO工具本身无关:
Android 10(API 29)及以上版本引入了分区存储机制,默认限制应用访问外部存储中的其他应用专属目录(Android/data、Android/obb等),即便申请了普通读写存储权限也无法访问这类路径。
排查步骤
- 确认运行设备的Android系统版本:API等级≥29时默认触发分区存储限制
- 检查App已申请权限:是否仅申请了普通的
READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限,未申请全量存储访问权限 - 确认业务需求:是否确实需要遍历
Android/data这类受限目录,仅访问公共媒体目录或自身应用专属目录即可满足需求的话不需要申请特殊权限
解决方案
方案1:无需访问受限目录(推荐)
修改遍历逻辑,自定义目录过滤器跳过受限路径,不要使用TrueFileFilter.INSTANCE全量遍历所有目录,示例代码:
// 自定义目录过滤器,跳过系统受限目录 val skipRestrictedDirFilter = FileFilter { dir -> val path = dir.absolutePath !path.contains("/Android/data") && !path.contains("/Android/obb") } val newFile = FileUtils.listFilesAndDirs( EXTERNAL_STORAGE, TrueFileFilter.INSTANCE, skipRestrictedDirFilter )
方案2:确实需要访问受限目录
根据App适配的系统版本申请对应权限:
- Android 10(API 29)适配:
在AndroidManifest.xml的application节点添加如下配置,临时关闭分区存储,使用旧版存储权限模型(该配置仅对Android 10设备生效,更高版本系统无效):
<application ... android:requestLegacyExternalStorage="true">
- Android 11(API 30)及以上适配:
需要申请特殊的全量文件访问权限,首先在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_ALL_FILES_ACCESS_PERMISSION) startActivity(intent) }
注意:如果应用需要上架Google Play,申请
MANAGE_EXTERNAL_STORAGE权限必须符合Google Play的政策要求,只有文件管理器、备份类等确实需要全量访问存储的应用才能通过审核。
内容的提问来源于stack exchange,提问作者Tarif Chakder
相关产品推荐
相关产品推荐

