Search code examples
javabytearrayoutputstreamgzipinputstreambytearrayinputstreamgzipoutputstream

Compressing byte[] to byte[] with GZIPOutputStream? Unexpected end of ZLIB input stream


I am trying to compress and array of bytes into another array of bytes using GZIPOutputStream (in Java).

This is my code:

@Test
public void testCompressBytes() throws IOException {
    final byte[] uncompressed = RandomStringUtils.randomAlphanumeric(100000 /* 100 kb */).getBytes();

    // compress
    byte[] compressed;
    try (InputStream is = new ByteArrayInputStream(uncompressed);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            OutputStream os = new GZIPOutputStream(baos)) {
        IOUtils.copy(is, os);  // org.apache.commons.io
        os.flush();
        compressed = baos.toByteArray();
    }       
    System.out.println("Size before compression = " + uncompressed.length + ", after = " + compressed.length);

    // decompress back
    byte[] decompressedBack;
    try (InputStream is = new GZIPInputStream(new ByteArrayInputStream(compressed));
            ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        IOUtils.copy(is, baos);  // EXCEPTION THROWN HERE
        baos.flush();
        decompressedBack = baos.toByteArray();
    }
        
    assertArrayEquals(uncompressed, decompressedBack);
}

And this is the output I'm getting:

Size before compression = 100000, after = 63920
java.io.EOFException: Unexpected end of ZLIB input stream

What could I be doing wrong?


Solution

  • Thanks, everybody! Although calling GZIPOutputStream::finish() before ByteArrayOutputStream::toByteArray() seems to do the trick, I believe it's better to completely close the GZIP stream first, which in turn forces us to keep ByteArrayOutputStream outside the try-with-resources clause.

    So, my reworked compression part looks like that now:

    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (InputStream is = new ByteArrayInputStream(uncompressed);
            GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
        IOUtils.copy(is, gzos);
    } catch (final IOException e) {
        throw new RuntimeException(e);
    }
    
    IOUtils.closeQuietly(baos);
    final byte[] compressed = baos.toByteArray();