Search code examples
javagogzipoutputstream

Why do gzip of Java and Go get different results?


Firstly, my Java version:

string str = "helloworld";
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream(str.length());
GZIPOutputStream localGZIPOutputStream = new GZIPOutputStream(localByteArrayOutputStream);
localGZIPOutputStream.write(str.getBytes("UTF-8"));
localGZIPOutputStream.close();
localByteArrayOutputStream.close();
for(int i = 0;i < localByteArrayOutputStream.toByteArray().length;i ++){
    System.out.println(localByteArrayOutputStream.toByteArray()[i]);
}

and output is:

31 -117 8 0 0 0 0 0 0 0 -53 72 -51 -55 -55 47 -49 47 -54 73 1 0 -83 32 -21 -7 10 0 0 0

Then the Go version:

var gzBf bytes.Buffer
gzSizeBf := bufio.NewWriterSize(&gzBf, len(str))
gz := gzip.NewWriter(gzSizeBf)
gz.Write([]byte(str))
gz.Flush()
gz.Close()
gzSizeBf.Flush()
GB := (&gzBf).Bytes()
for i := 0; i < len(GB); i++ {
    fmt.Println(GB[i])
}

output:

31 139 8 0 0 9 110 136 0 255 202 72 205 201 201 47 207 47 202 73 1 0 0 0 255 255 1 0 0 255 255 173 32 235 249 10 0 0 0

Why?

I thought it might be caused by different byte reading methods of those two languages at first. But I noticed that 0 can never convert to 9. And the sizes of []byte are different.

Have I written wrong code? Is there any way to make my Go program get the same output as the Java program?

Thanks!


Solution

  • From RFC 1952, the GZip file header is structured as:

    +---+---+---+---+---+---+---+---+---+---+
    |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
    +---+---+---+---+---+---+---+---+---+---+
    

    Looking at the output you've provided, we have:

                              |    Java |          Go
    ID1                       |      31 |          31
    ID2                       |     139 |         139
    CM (compression method)   |       8 |           8
    FLG (flags)               |       0 |           0
    MTIME (modification time) | 0 0 0 0 | 0 9 110 136
    XFL (extra flags)         |       0 |           0
    OS (operating system)     |       0 |         255
    

    So we can see that Go is setting the modification time field of the header, and setting the operating system to 255 (unknown) rather than 0 (FAT file system). In other respects they indicate that the file is compressed in the same way.

    In general these sorts of differences are harmless. If you want to determine if two compressed files are the same, then you should really compare the decompressed versions of the files though.