Android读取文本文件遇EACCES权限拒绝错误,求解决方案
你遇到的这个权限拒绝问题,大多是Android 10及以上版本的**分区存储(Scoped Storage)**机制导致的——哪怕你已经在Manifest声明了权限、也申请了运行时权限,系统依然会限制对外部存储任意目录的直接访问。下面是针对性的解决方案:
1. 适配Android 10(API 29)的临时兼容方案
Android 10默认启用分区存储,若想继续用传统的文件路径访问方式,需要在AndroidManifest.xml的<application>标签中添加兼容属性:
<application android:name=".MyApplication" ... android:requestLegacyExternalStorage="true"> ... </application>
这个属性会让应用以Android 9及以下的存储逻辑运行,绕过分区存储限制,但这只是临时过渡方案,Android 11及以上会有更严格的限制。
2. 必须处理权限请求的回调逻辑
你只写了权限检查和请求的代码,但缺少权限申请结果的回调处理。必须在Activity中重写onRequestPermissionsResult方法,确认权限被授予后再执行文件读取:
private static final int STORAGE_PERMISSION_REQUEST = 1001; @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == STORAGE_PERMISSION_REQUEST) { // 检查读写权限是否全部授予 boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { // 权限通过,执行文件读取逻辑 readXConfigFile(); } else { Toast.makeText(this, "存储权限被拒绝,无法读取文件", Toast.LENGTH_SHORT).show(); } } }
⚠️ 注意:不要在调用requestPermissions后立即执行文件读取,必须等待回调确认权限已授予。
3. Android 11(API 30)及以上的特殊处理
Android 11开始,requestLegacyExternalStorage不再生效。如果需要访问外部存储的任意目录,你需要申请MANAGE_EXTERNAL_STORAGE权限:
步骤1:在Manifest中添加权限
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
步骤2:引导用户手动开启权限
这个权限无法通过普通运行时请求获取,需要跳转到系统设置页面让用户手动开启:
private static final int MANAGE_STORAGE_REQUEST = 1002; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (!Environment.isExternalStorageManager()) { Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivityForResult(intent, MANAGE_STORAGE_REQUEST); } else { // 已获得权限,执行文件读取 readXConfigFile(); } }
然后在onActivityResult中确认权限状态:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == MANAGE_STORAGE_REQUEST) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Environment.isExternalStorageManager()) { readXConfigFile(); } else { Toast.makeText(this, "需要授予全存储访问权限才能读取文件", Toast.LENGTH_SHORT).show(); } } } }
4. 提前确认目录是否存在
在创建File对象前,先确保sos目录已存在,避免因目录不存在导致的间接权限报错:
File sdcard = Environment.getExternalStorageDirectory(); File sosDir = new File(sdcard, "sos"); // 创建多级目录(如果不存在) if (!sosDir.exists()) { boolean dirCreated = sosDir.mkdirs(); if (!dirCreated) { Toast.makeText(this, "无法创建sos目录", Toast.LENGTH_SHORT).show(); return; } } File file = new File(sosDir, "xconfig.txt");
长期适配建议
以上都是兼容传统存储方式的临时方案,Google推荐从Android 10开始适配分区存储或存储访问框架(SAF):
- 如果是媒体文件,使用
MediaStoreAPI访问 - 如果是非媒体文件,使用SAF让用户主动选择文件/目录,无需依赖特殊权限
内容的提问来源于stack exchange,提问作者Piyush Chandra




