首页 > 解决方案 > 如何正确关闭嵌套的 ZipInputStreams?

问题描述

我正在使用以下代码在内存中读取嵌套的 zip 文件(包含多个其他 zip 文件的 zip 文件)

try (ZipInputStream zis = new ZipInputStream(inputStream)) {
   ZipEntry zipEntry;
   while ((zipEntry = zis.getNextEntry()) != null) {
      if (zipEntry.getName().endsWith(".zip")) {
         ZipInputStream nestedZis = new ZipInputStream(zis);
         Pojo myPojo = myPojoReader.readFrom(nestedZis);
      }
   }
   zis.closeEntry();
}

该代码工作正常,但我收到 StrictMode 违规错误(在 Android 中),因为嵌套流nestedZis未正确关闭。

问题:

  1. 我不能更早地实例化它,因为我必须先调用zis.getNextEntry()才能正确定位外部流
  2. 我不能在 while 循环中关闭它,因为这也会关闭外部 ZipInputStream

是否有正确处理资源的解决方案?

请注意,我明确没有询问此处描述的链式流。由于上面提到的第一个问题,我不能在 try-with-resources 语句中包含嵌套流。

注意我不能使用ZipFile,因为我只能将 Inputstream 作为我的初始资源并且无权访问文件。

标签: javatry-with-resourceszipinputstream

解决方案


感谢@k314159 提供的使用 Apache 的提示,CloseShieldInputStream它是 Apache Commons IO 库的一部分,我将代码更改为:

try (ZipInputStream zis = new ZipInputStream(inputStream)) {
   ZipEntry zipEntry;
   while ((zipEntry = zis.getNextEntry()) != null) {
      if (zipEntry.getName().endsWith(".zip")) {
         try (CloseShieldInputStream cloned = CloseShieldInputStream.wrap(zis); ZipInputStream nestedZis = new ZipInputStream(cloned)) {
            Pojo myPojo = myPojoReader.readFrom(nestedZis);
         }
      }
   }
   zis.closeEntry();
}

这保留了我的代码的功能,同时还通过了 Android 的 StrictMode 验证。

CloseShieldInputStream是一个代理流,可防止底层输入流被关闭。

注意还有一个CloseShieldOutputStream我现在用于生成嵌套 zip。


推荐阅读