Android外部写入权限问题:读写文本文件遇权限拒绝异常
解决Android读写文件时的"Permission denied"问题
嘿,我之前也踩过这个权限坑,折腾了好一会儿才理顺,给你几个核心的排查和解决步骤:
1. 先确认清单文件的权限声明
首先,你需要在AndroidManifest.xml里添加必要的存储权限,还要注意不同Android版本的特殊配置:
<!-- 针对Android 10以下版本的写入权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 如果你的targetSdkVersion >= 30(Android 11+),需要添加这个来兼容旧存储模式 --> <application ... android:requestLegacyExternalStorage="true"> ... </application>
注意:从Android 13开始,WRITE_EXTERNAL_STORAGE已经被废弃,改用更细分的权限,但如果是兼容旧版本,还是需要保留上面的配置。
2. 动态申请危险权限(Android 6.0+)
Android 6.0(API 23)之后,存储权限属于危险权限,只在清单里声明是不够的,必须在代码里动态请求用户授权:
// 在你的Activity里添加权限检查逻辑 private static final int REQUEST_STORAGE_PERMISSION = 100; private void checkStoragePermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { // 如果没有权限,发起申请 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERMISSION); } else { // 权限已授予,执行文件读写操作 buttonSave(null); } } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_STORAGE_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 用户同意权限,执行保存操作 buttonSave(null); } else { // 用户拒绝权限,提示或者做其他处理 Toast.makeText(this, "需要存储权限才能保存文件", Toast.LENGTH_SHORT).show(); } } }
然后你需要修改按钮的点击逻辑,先调用checkStoragePermission(),而不是直接执行buttonSave。
3. 更推荐的文件存储路径(避开权限问题)
其实如果这个文件是你的应用专属的(比如只给你的应用用,卸载后可以删除),完全不需要申请外部存储权限,改用应用专属的外部存储路径:
public void buttonSave(View view) { // 获取应用专属的外部存储目录,不需要额外权限 File directoryFile = getExternalFilesDir(null); // 如果目录不存在会自动创建,不用手动mkdirs() File file = new File(directoryFile, "savefile.txt"); try { if (!file.exists()) { file.createNewFile(); } // 这里添加写入文件的逻辑,比如用FileWriter FileWriter writer = new FileWriter(file); writer.write("你要保存的内容"); writer.close(); Toast.makeText(this, "文件保存成功", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "保存失败:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } }
这个路径的好处是不需要任何权限,而且系统会自动管理,卸载应用时会一起删除这个目录下的文件,更符合Android的存储规范。
4. 排查异常细节
如果还是报错,一定要把异常的完整堆栈信息打出来,比如在catch块里加e.printStackTrace(),这样能看到具体是哪一行出错,比如目录创建失败还是文件写入失败,有助于精准定位问题。
内容的提问来源于stack exchange,提问作者Andrew Pienaar
相关产品推荐
相关产品推荐

