Android Studio无法打开txt到EditText:权限拒绝错误持续触发
问题根源
从Android 10(API 29)开始,系统启用分区存储(Scoped Storage),默认禁止直接通过file:// URI或文件路径访问外部存储的文件——哪怕你申请了READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE权限。你存入SQLite的应该是普通文件路径或file:// URI,这类URI没有持久访问权限,重启应用或系统后就会触发权限拒绝错误。
可行解决方案
方案1:用MediaStore API访问DCIM目录文件
DCIM属于系统媒体目录,可通过MediaStore直接查询、访问,API 30+无需READ_EXTERNAL_STORAGE权限,低版本仍需申请:
- 查询获取目标txt文件的
content://URI(存入SQLite的应该是这个URI):String selection = MediaStore.Files.FileColumns.DISPLAY_NAME + " = ? AND " + MediaStore.Files.FileColumns.RELATIVE_PATH + " = ?"; String[] selectionArgs = {"目标文件名.txt", "DCIM/sheet_music/"}; Cursor cursor = getContentResolver().query( MediaStore.Files.getContentUri("external"), new String[]{MediaStore.Files.FileColumns._ID}, selection, selectionArgs, null ); if (cursor != null && cursor.moveToFirst()) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)); Uri contentUri = ContentUris.withAppendedId(MediaStore.Files.getContentUri("external"), id); // 将contentUri存入SQLite,后续用它访问文件 cursor.close(); } - 通过
contentUri读取文件内容到EditText:try (InputStream is = getContentResolver().openInputStream(contentUri); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } editText.setText(sb.toString()); } catch (IOException e) { e.printStackTrace(); } - 写入文件同理,调用
getContentResolver().openOutputStream(contentUri)获取输出流即可。
方案2:迁移文件到应用私有外部存储
如果这些txt文件仅属于你的应用,可把它们移到应用私有外部目录,这里的文件无需任何权限就能直接访问,路径也能安全存入SQLite:
- 迁移文件示例:
File sourceFile = new File(Environment.getExternalStorageDirectory(), "DCIM/sheet_music/目标文件.txt"); File destDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS); if (destDir != null) { File destFile = new File(destDir, "sheet_music/目标文件.txt"); if (!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } // 复制文件(需处理IO异常) Files.copy(sourceFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING); // 后续用destFile的路径直接访问,存入SQLite }
方案3:获取目录持久权限(保留原存储位置)
如果必须保留文件在DCIM/sheet_music目录,可通过一次目录选择获取持久访问权限,之后无需重复选择:
- 启动目录选择器:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); startActivityForResult(intent, REQUEST_CODE_TREE); - 在
onActivityResult中获取目录URI并持久化权限:@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_TREE && resultCode == RESULT_OK) { Uri treeUri = data.getData(); // 持久化权限,重启应用仍有效 getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); // 将treeUri存入SharedPreferences或SQLite } } - 后续通过
DocumentFile访问目录下的文件:DocumentFile treeDoc = DocumentFile.fromTreeUri(this, treeUri); if (treeDoc != null) { DocumentFile targetFile = treeDoc.findFile("目标文件.txt"); if (targetFile != null) { Uri fileUri = targetFile.getUri(); // 用fileUri读取/写入文件,方法同方案1 } }
关键注意点
- 不要使用
MANAGE_EXTERNAL_STORAGE权限,该权限仅开放给文件管理器类应用,普通应用使用会被Google Play限制上架。 - 存入SQLite的必须是
content://类型的URI(而非file://或本地路径),且需确保URI有持久访问权限:方案1的MediaStore URI天然持久,方案3的目录URI需调用takePersistableUriPermission。
内容的提问来源于stack exchange,提问作者kiteandwindsurfer
相关产品推荐
相关产品推荐

