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
相关产品推荐
相关产品推荐

