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

Android 11+ 下将应用专属目录缓存PDF保存至共享存储(Java)

Android 11+ 下将应用专属缓存PDF保存到共享存储的实现

一、权限准备

针对Android 11及以上版本,操作共享存储无需申请WRITE_EXTERNAL_STORAGE权限,仅需在AndroidManifest.xml中声明必要的读取权限(针对Android 13+的媒体类型):

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Android 13+ 媒体类型权限,PDF等文档无需额外权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />

二、获取应用专属缓存中的PDF文件

先拿到应用缓存目录下的源PDF文件对象:

// 内部缓存目录,仅当前应用可访问
File sourcePdf = new File(getCacheDir(), "cached_file.pdf");
// 或外部缓存目录(需确保外部存储可用)
// File sourcePdf = new File(getExternalCacheDir(), "cached_file.pdf");

if (!sourcePdf.exists() || !sourcePdf.isFile()) {
    // 处理文件不存在或不是文件的情况
    return;
}

三、方案1:通过MediaStore保存到公共文档目录(推荐)

使用MediaStore API是Android 11+操作共享存储的标准方式,以下代码将PDF保存到系统Download目录的子文件夹中:

String targetFileName = "saved_pdf_file.pdf";
ContentValues contentValues = new ContentValues();

// 设置文件信息
contentValues.put(MediaStore.Downloads.DISPLAY_NAME, targetFileName);
contentValues.put(MediaStore.Downloads.MIME_TYPE, "application/pdf");
// 指定在Download目录下的子目录,系统会自动创建
contentValues.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/MyAppPDFs");

ContentResolver resolver = getContentResolver();
Uri targetUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues);

if (targetUri == null) {
    // 插入文件记录失败,处理错误
    return;
}

// 复制源文件内容到共享存储
try (InputStream inputStream = new FileInputStream(sourcePdf);
     OutputStream outputStream = resolver.openOutputStream(targetUri)) {
    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = inputStream.read(buffer)) != -1) {
        outputStream.write(buffer, 0, bytesRead);
    }
    // 文件保存成功,可提示用户
} catch (IOException e) {
    e.printStackTrace();
    // 复制失败,删除已创建的空文件记录
    resolver.delete(targetUri, null, null);
}

四、方案2:用SAF让用户选择保存位置

如果需要让用户自定义保存路径,使用存储访问框架(SAF):

// 注册Activity结果回调(AndroidX推荐方式)
ActivityResultLauncher<Intent> savePdfLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == RESULT_OK && result.getData() != null) {
            Uri selectedUri = result.getData().getData();
            if (selectedUri != null) {
                try (InputStream inputStream = new FileInputStream(sourcePdf);
                     OutputStream outputStream = getContentResolver().openOutputStream(selectedUri)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                    // 保存成功
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
);

// 启动SAF选择保存位置
Intent saveIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
saveIntent.addCategory(Intent.CATEGORY_OPENABLE);
saveIntent.setType("application/pdf");
saveIntent.putExtra(Intent.EXTRA_TITLE, "saved_pdf_file.pdf");
savePdfLauncher.launch(saveIntent);

五、关键注意事项

  • 应用专属目录的文件为私有资源,复制到共享存储后其他应用可访问
  • 禁止使用Environment.getExternalStorageDirectory()等废弃API,Android 11+已限制直接访问根目录
  • 仅在批量操作非媒体/文档文件时,才需要申请MANAGE_EXTERNAL_STORAGE权限,该权限需用户手动在设置中开启,不推荐常规场景使用
  • 复制文件时必须处理IO异常,避免残留空文件记录

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 19:37:46