How to prevent ZipInputStream from being closed by after a XSLT transform?

3.9k Views Asked by At

I have a ZipInputStream that contains a number of XML files that I want to apply a transform to. The following piece of code loads the XSLT and ZIP files and loops through the ZIP entries, attempting to apply the transform to each one. However it appears the transform function is closing the input stream after performing the transform, causing the getNextEntry() function to fail because the stream is closed.

Is there is a simple way around this problem (to keep the input stream open allowing the ZipInputStream to move to the next entry) or am I missing something more fundamental here?

TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(new StreamSource(xsltFileName));

FileInputStream fis = new FileInputStream(fileName);
ZipInputStream zis = new ZipInputStream(fis);
ZipEntry ze = null;

while ((ze = zis.getNextEntry()) != null)
{
    String newFileName = ze.getName();
    transformer.transform(new StreamSource(zis), new StreamResult(new FileOutputStream(newFileName)));
}

I have attempted to search for a solution but don't seem to be coming up with anything that makes sense. I'd appreciate any ideas or feedback.

5

There are 5 best solutions below

3
On BEST ANSWER

One possible solution is to extend ZipInputStream (it's not final) and override the close method to do nothing. Of course you need to make sure then to close it your self. You can do that with a second custom close method that simply calls super.close().

class MyZIS extends ZipInputStream {

    public MyZIS(InputStream in) {
        super(in);
    }

    @Override
    public void close() throws IOException {
    }

    public void myClose() throws IOException {
        super.close();
    }
}
1
On

Perhaps what you need to do is then read the zip input into a temporary buffer, then use that as the source to the transformer. My understanding is that the transformer needs to read the entire stream to determine what the transform should be, therefore, even if it didn't close the input stream, the next read would hit EOF.

Perhaps something like this? (no optimization has been done)

    byte[] bytes = new byte[(int) entry.getSize()];
    zis.read(bytes);
    ByteArrayInputStream out = new ByteArrayInputStream(bytes);
    transformer.transform(new StreamSource(zis), new StreamResult(new FileOutputStream(newFileName)));    }
4
On

Generally the accepted protocol is that "he who creates an input stream should close it after use" and it appears your XSLT processor (Xalan?) isn't following this convention. If that's the case, then a workaround (apart from moving to a different XSLT processor!) is to write a filter stream that wraps the ZipInputStream and passes on all calls to the underlying ZipInputStream, except for the close() call which it intercepts.

4
On

You should actually be using the class ZipFile for reading the zip archive. Then you get the inputstream for the zip entry like this:

zipfile.getInputStream(zipEntry);
0
On

There is a property you can set : IsStreamOwner, when this is false the underlying stream will not be closed.