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

Android 11及以上:通过Scoped Storage创建并保存Zip文件

解决Android 11+ Scoped Storage下将内部存储文件压缩并保存到公共目录的问题

问题诊断

你的代码核心问题在于错误地将FileOutputStream转为字符串传递给压缩方法,导致压缩内容无法正确写入到Scoped Storage授权的URI对应的文件中。另外还有冗余代码和无效的异常处理,阻碍问题排查。

修正后的完整代码实现

首先确保你正确定义并初始化ActivityResultLauncher:

// Activity成员变量
private ActivityResultLauncher<Intent> someActivityResultLauncher;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    someActivityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        result -> {
            if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                Uri uri = result.getData().getData();
                try {
                    createDocument(uri);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    Toast.makeText(this, "文件创建失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
                }
            }
        }
    );
}

然后修改createDocument方法,修复流传递问题并优化逻辑:

@Override
public void onClick(View v) {
    String dateiname = "Backup.zip";

    Intent intentm = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intentm.addCategory(Intent.CATEGORY_OPENABLE);
    intentm.setType("application/zip");
    intentm.putExtra(Intent.EXTRA_TITLE, dateiname);
    // 引导用户默认进入Downloads目录,提升体验
    intentm.putExtra(DocumentsContract.EXTRA_INITIAL_URI, MediaStore.Downloads.EXTERNAL_CONTENT_URI);
    someActivityResultLauncher.launch(intentm);
}

private void createDocument(Uri uri) throws FileNotFoundException {
    // 构建内部存储中待压缩文件的完整路径
    String inputFilePath = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "Test.txt").getAbsolutePath();
    String[] filesToZip = new String[]{inputFilePath};

    try (ParcelFileDescriptor fileDescriptor = getContentResolver().openFileDescriptor(uri, "w");
         FileOutputStream fileOutputStream = new FileOutputStream(fileDescriptor.getFileDescriptor())) {

        ZipManager zipManager = new ZipManager();
        // 直接传递FileOutputStream给压缩方法,禁止转为字符串
        zipManager.zip(filesToZip, fileOutputStream);

        Toast.makeText(this, "Zip文件已保存成功", Toast.LENGTH_LONG).show();

    } catch (IOException e) {
        e.printStackTrace();
        Toast.makeText(this, "压缩失败:" + e.getMessage(), Toast.LENGTH_SHORT).show();
    }
}

关键注意事项

  • 输出流传递要求:你的ZipManager.zip()方法必须接受OutputStream类型参数,如果是自定义类,确保其内部逻辑是直接写入到传入的输出流中,而非解析字符串路径。
  • Scoped Storage合规性:通过Intent.ACTION_CREATE_DOCUMENT让用户主动选择保存位置,是Android 11+下写入公共目录的唯一合规方式,禁止直接通过文件路径操作公共目录文件。
  • 资源自动管理:使用try-with-resources语法自动关闭ParcelFileDescriptor和FileOutputStream,避免资源泄漏。
  • 异常排查:替换空catch块,打印异常栈并给用户明确提示,方便定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 04:00:26