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

如何在Android 13及兼容5/6/7低版本系统中低权限保存文件至外部存储?

适配Android 5/6/7至13的低权限文件保存方案

以下是针对不同Android版本的低权限文件保存方案,覆盖API 21(Android 5)至API 33(Android 13):

一、应用私有目录存储(无权限要求)

所有版本均无需申请存储权限,文件仅当前应用可访问,卸载应用时自动删除,适合仅应用自用的文件。

1. 内部私有目录

存储在系统分配的应用专属内部空间:

// 获取内部文件目录,创建自定义文件
File internalFile = new File(getFilesDir(), "app_data.txt");
// 获取内部缓存目录,适合临时文件
File internalCache = new File(getCacheDir(), "temp_cache.txt");

2. 外部私有目录

存储在外部存储的应用专属分区(Android 4.4+支持):

// 获取外部文件目录,可指定子目录如文档、图片
File externalDocDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
File externalFile = new File(externalDocDir, "app_doc.txt");
// 获取外部缓存目录
File externalCacheDir = getExternalCacheDir();

二、公共媒体目录存储(按需申请权限)

适合保存图片、视频、音频等媒体文件,允许其他应用访问,权限要求随版本变化:

Android 10(API 29)及以上

无需申请WRITE_EXTERNAL_STORAGE权限,直接通过MediaStore API插入文件:

ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DISPLAY_NAME, "my_photo.jpg");
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
// 指定存储路径到公共图片目录下的自定义子文件夹
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyApp");

Uri mediaUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (mediaUri != null) {
    try (OutputStream os = getContentResolver().openOutputStream(mediaUri)) {
        // 写入文件内容
        os.write("media content".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Android 5-9(API 21-28)

需要申请WRITE_EXTERNAL_STORAGE权限,Android 6(API 23)及以上需动态申请:

// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    // 动态申请权限
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
    return;
}

// 写入公共图片目录
File publicPicDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
if (!publicPicDir.exists()) publicPicDir.mkdirs();
File publicFile = new File(publicPicDir, "my_photo.jpg");

try (FileOutputStream fos = new FileOutputStream(publicFile)) {
    fos.write("media content".getBytes());
} catch (IOException e) {
    e.printStackTrace();
}

三、存储访问框架(SAF)通用方案(无权限要求)

Android 4.4(API 19)及以上支持,无需申请存储权限,由用户选择存储目录,适配所有目标版本到13,适合需要用户自主选择存储位置的场景:

1. 打开目录选择器

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 200);

2. 处理选择结果并操作文件

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 200 && resultCode == RESULT_OK && data != null) {
        Uri treeUri = data.getData();
        // 持久化权限,重启应用后仍可访问
        getContentResolver().takePersistableUriPermission(treeUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        
        // 创建新文件
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
        DocumentFile newFile = pickedDir.createFile("text/plain", "user_selected_file.txt");
        
        if (newFile != null) {
            try (OutputStream os = getContentResolver().openOutputStream(newFile.getUri())) {
                os.write("SAF saved content".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

方案选型建议

  • 仅应用自用文件:优先选应用私有目录,无权限问题,适配最简单。
  • 共享媒体文件:选公共媒体目录,Android10+无需权限,兼容性好。
  • 用户自主选存储位置或操作非媒体公共文件:选SAF框架,完全无权限要求,跨版本通用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 03:10:16