35

There is something wrong with GZIPInputStream or GZIPOutputStream. Just please read the following code (or run it and see what happens):

def main(a: Array[String]) {
    val name = "test.dat"
    new GZIPOutputStream(new FileOutputStream(name)).write(10)
    println(new GZIPInputStream(new FileInputStream(name)).read())
}

It creates a file test.dat, writes a single byte 10 formatting by GZIP, and read the byte in the same file with the same format.

And this is what I got running it:

Exception in thread "main" java.io.EOFException: Unexpected end of ZLIB input stream
    at java.util.zip.InflaterInputStream.fill(Unknown Source)
    at java.util.zip.InflaterInputStream.read(Unknown Source)
    at java.util.zip.GZIPInputStream.read(Unknown Source)
    at java.util.zip.InflaterInputStream.read(Unknown Source)
    at nbt.Test$.main(Test.scala:13)
    at nbt.Test.main(Test.scala)

The reading line seems going the wrong way for some reason.

I googled the error Unexpected end of ZLIB input stream and found some bug reports to Oracle, which were issued around 2007-2010. So I guess the bug still remains in some way, but I'm not sure if my code is right, so let me post this here and listen to your advice. Thank you!

Ryoichiro Oka
  • 1,949
  • 2
  • 13
  • 20

1 Answers1

54

You have to call close() on the GZIPOutputStream before you attempt to read it. The final bytes of the file will only be written when the stream object is actually closed.

(This is irrespective of any explicit buffering in the output stack. The stream only knows to compress and write the last bytes when you tell it to close. A flush() won't help ... though calling finish() instead of close() should work. Look at the javadocs.)

Here's the correct code (in Java);

package test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class GZipTest {

    public static void main(String[] args) throws
                FileNotFoundException, IOException {
        String name = "/tmp/test";
        GZIPOutputStream gz = new GZIPOutputStream(new FileOutputStream(name));
        gz.write(10);
        gz.close();       // Remove this to reproduce the reported bug
        System.out.println(new GZIPInputStream(new FileInputStream(name)).read());
    }
}

(I've not implemented resource management or exception handling / reporting properly as they are not relevant to the purpose of this code. Don't treat this as an example of "good code".)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • What if I have created an instance of FileOutputStream here before initializing GZIPOutputStream ? Do I need to call close() on this object as well? Because my code is throwing same error with close being called. Also does the order matter of GZIPOutputStream and FileOutputStream close() call? – coretechie Sep 09 '15 at 07:04
  • No you don't. Calling `close` on the `GZIPOutputStream` object will call close on the `FileOutputStream` that it wraps. (There is a theoretical resource leak if construction of the `GZIPOutputStream` fails, but I think that would only be noticeable if you caught / recovered from `Error` ... which is a bad thing to do.) – Stephen C Sep 09 '15 at 08:03
  • *"Also does the order matter of GZIPOutputStream and FileOutputStream close()"*. Yes. It matters. If you close the FileOutputStream first, then the close on the GZIPOutputStream will throw an exception ... because it can't write out the remainder of the data to the closed FileOutputStream. – Stephen C Feb 13 '17 at 13:55