如何正确关闭嵌套的 ZipInputStreams?

Posted

技术标签:

【中文标题】如何正确关闭嵌套的 ZipInputStreams?【英文标题】:How to correctly close nested ZipInputStreams? 【发布时间】:2021-07-27 11:58:58 【问题描述】:

我正在使用以下代码读取一个嵌套的 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();

代码运行良好,但由于嵌套流 nestedZis 未正确关闭,因此出现 StrictMode 违规错误(在 android 中)。

问题:

    我无法提前实例化它,因为我必须先调用 zis.getNextEntry() 才能正确定位外部流 我无法在 while 循环中关闭它,因为这也会关闭外部 ZipInputStream

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

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

注意我不能使用ZipFile,因为我只能获取一个输入流作为我的初始资源并且无权访问文件。

【问题讨论】:

你需要把zip.closeEntry()放在while循环里面。 这不会改变任何事情,因为getNextEntry() 在内部调用closeEntry() 你是对的。 Apache 的 CloseShieldInputStream 有帮助吗? 确实如此!谢谢你的提示。您想将此添加为答案以便我接受吗? 我很高兴我的想法有所帮助,但我对 StrictMode 不熟悉,所以我将把它留给别人(可能是你自己)写一个好的答案。 【参考方案1】:

感谢 @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。

【讨论】:

以上是关于如何正确关闭嵌套的 ZipInputStreams?的主要内容,如果未能解决你的问题,请参考以下文章

如何关闭嵌套在线程内的线程?

jdbc如何在嵌套查询中处理连接的关闭问题

展开分解成重复嵌套组件的字符串[关闭]

具有自定义数据结构的 SwiftUI 列表,每个循环都嵌套 [关闭]

如何在带有嵌套字典的嵌套循环中正确使用字典“.update”函数[重复]

如何计算两个嵌套数组的精度和召回率 [关闭]