Preferred way to use Java ZipOutputStream and BufferedOutputStream

jjathman picture jjathman · Jan 22, 2013 · Viewed 75.2k times · Source

In Java does it matter whether I instantiate a ZipOutputStream first, or the BufferedOutputStream first? Example:

FileOutputStream dest = new FileOutputStream(file);
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(dest));

// use zip output stream to write to

Or:

FileOutputStream dest = new FileOutputStream(file);
BufferedOutputStream out = new BufferedOutputStream(new ZipOutputStream(dest));

// use buffered stream to write to

In my non-scientific timings I can't seem to tell much of a difference here. I can't see anything in the Java API that says if one of these ways is necessary or preferred. Any advice? It seems like compressing the output first and then buffering it for writes would be more efficient.

Answer

Daniel Dinnyes picture Daniel Dinnyes · Jun 19, 2013

You should always wrap the BufferedOutputStream with the ZipOutputStream, never the other way around. See the below code:

FileOutputStream fos = new FileOutputStream("hello-world.zip");
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos);

try {
    for (int i = 0; i < 10; i++) {
        // not available on BufferedOutputStream
        zos.putNextEntry(new ZipEntry("hello-world." + i + ".txt"));
        zos.write("Hello World!".getBytes());
        // not available on BufferedOutputStream
        zos.closeEntry();
    }
}
finally {
    zos.close();
}

As the comments say the putNextEntry() and closeEntry() methods are not available on the BufferedOutputStream. Without calling those methods ZipOutputStream throws an exception java.util.zip.ZipException: no current ZIP entry.

For the sake of completeness, it is worth noting that the finally clause only calls close() on the ZipOutputStream. This is because by convention all built-in Java output stream wrapper implementations propagate closing.

EDIT

I just tested it the other way around. It turns out that wrapping a ZipOutputStream with BufferedOutputStream and then only calling write() on it (without creating / closing entries) will not throw a ZipException. Instead the resulting ZIP file will be corrupt, without any entries inside it.