javatry-with-resourceszipinputstream

How to correctly close nested ZipInputStreams?


I am reading a nested zip file (a zip file containing multiple other zip files) in memory with the following code

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();
}

The code works fine, but I get StrictMode violation errors (in Android) since the nested Stream nestedZis is not closed properly.

The problems:

  1. I cannot instantiate it earlier since I have to call zis.getNextEntry() before in order to position the outer stream correctly
  2. I cannot close it within the while loop since that would also close the outer ZipInputStream

Is there a solution that handles the resources correctly?

Note I am explicitly not asking about chained streams as described here. I cannot include the nested stream in the try-with-resources statement because of the first problem mentioned above.

Note I can not use ZipFile since I can only get an Inputstream as my initial resource and do not have access to the File.


Solution

  • Thanks to the tip from @k314159 to use Apache's CloseShieldInputStream which is part of Apache Commons IO library I changed my code to:

    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();
    }
    

    This preserves the functionality of my code while also passing Android's StrictMode verifications.

    The CloseShieldInputStream is a proxy stream that prevents the underlying input stream from being closed.

    Note There also is a CloseShieldOutputStream which I now use for the generating of the nested zip.