You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android SDK31创建外置存储文件报Operation not permitted错误

问题根因

该报错由Android 11(API 30)及以上版本强制启用的**分区存储(Scoped Storage)**机制导致:

  • 当compileSdkVersion与targetSdkVersion均设置为31(即Android 12)时,旧版的WRITE_EXTERNAL_STORAGE、READ_EXTERNAL_STORAGE权限不再授予外置存储根目录、其他应用专属目录的直接读写权限,你代码中通过Environment.getExternalStorageDirectory()访问根路径创建文件的操作会被系统直接拦截,抛出IOException: Operation not permitted异常。
  • 你之前配置的静态权限声明、API23+动态权限申请逻辑,仅适配了Android 6.0到Android 10的存储规则,没有覆盖API30+的存储权限变更。
适配方案

根据你的文件使用场景,选择对应方案即可:

方案1:使用应用专属外置目录(无权限要求,优先推荐)

如果存储的文件不需要给其他应用访问、不需要在应用卸载后保留,直接使用应用专属的外置存储目录即可,无需申请任何存储权限,系统不会拦截该目录下的文件操作:

// 目录路径为 /sdcard/Android/data/你的应用包名/files/
File file = new File(getExternalFilesDir(null), "dummy.txt");
if (!file.exists()){
    file.createNewFile();
}

常用的专属外置目录还有两个:

  • 缓存目录:调用context.getExternalCacheDir()获取,对应路径/sdcard/Android/data/你的应用包名/cache/,系统存储空间不足时会自动清理该目录下的文件
  • 持久化文件目录:即上述getExternalFilesDir()目录,应用卸载时该目录下的所有文件会被系统同步删除

方案2:访问系统公共目录(适合共享类文件)

如果需要将文件存放到系统公共目录(如DCIM、Pictures、Download、Documents等),供其他应用访问或者在卸载后保留,不需要申请存储权限,通过系统提供的API操作即可:

  • 图片、视频、音频类媒体文件:通过MediaStore API将文件插入到对应公共媒体集合
  • 文档、安装包等非媒体文件:通过存储访问框架(SAF)拉起系统文件选择器,让用户指定保存位置,拿到返回的Uri后通过ContentResolver写入文件

方案3:临时关闭分区存储(仅作过渡兼容,不推荐)

如果短时间内无法完成分区存储适配,可以在Manifest清单文件的<application>标签下添加如下属性,临时启用旧版存储访问模式,该配置在targetSdk 31版本上仍可生效,但后续高版本Android系统会逐步移除该兼容项:

<application
    android:requestLegacyExternalStorage="true"
    <!-- 其余原有属性 -->
>
    <!-- 原有组件声明 -->
</application>

注意:该方案仅适合版本迭代过渡期使用,主流应用市场在审核高targetSdk版本应用时,会逐步要求强制适配分区存储,不建议长期依赖该配置。

方案4:申请全存储访问权限(仅适合特定功能场景)

如果你的应用是文件管理器、数据备份、杀毒类工具,确实需要访问外置存储全目录的所有文件,可以申请特殊的MANAGE_EXTERNAL_STORAGE权限:

  1. 先在Manifest中添加权限声明:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
  1. 动态判断权限状态,未授权时引导用户跳转到系统设置页开启:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (!Environment.isExternalStorageManager()) {
        // 未授权,跳转到系统所有文件访问授权页
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, REQUEST_CODE_MANAGE_STORAGE);
    } else {
        // 已获得全存储访问权限,可以正常操作根目录文件
        File file = new File(Environment.getExternalStorageDirectory(), "dummy.txt");
        if (!file.exists()){
            file.createNewFile();
        }
    }
}

注意:该权限属于特殊敏感权限,如果应用没有合理的全存储访问需求,提交应用市场审核时会被直接拒绝。


内容的提问来源于stack exchange,提问作者tushar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 12:27:45