You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GZIPOutputStream压缩byte[]报错:Unexpected end of ZLIB输入流

问题原因及解决方法

你的问题出在GZIP压缩流未完成收尾操作,导致压缩后的字节数组不完整,解压时无法识别GZIP的结束标记,从而抛出EOFException。

具体分析

GZIPOutputStream在完成数据写入后,需要写入GZIP格式的结束校验信息(包括CRC校验值、原始数据长度等),这些信息是解压时验证数据完整性的必要部分。你当前只调用了os.flush(),但flush()仅会将缓冲区中的数据输出到ByteArrayOutputStream,并不会触发GZIP的收尾逻辑;同时你在try-with-resources块内部就调用了baos.toByteArray(),此时GZIPOutputStream还未被关闭(try-with-resources会在块执行完毕后才自动关闭资源),因此压缩数据缺少关键的结束标识。

两种修复方案

方案1:主动调用finish()完成压缩流

在数据复制完成后,显式调用GZIPOutputStream.finish()触发收尾逻辑,再获取压缩后的字节数组:

@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);
        os.finish(); // 关键:完成GZIP压缩流,写入结束校验信息
        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);
        decompressedBack = baos.toByteArray();
    }
        
    assertArrayEquals(uncompressed, decompressedBack);
}

方案2:利用try-with-resources自动关闭的特性

将ByteArrayOutputStream的声明移到try-with-resources块外,等GZIPOutputStream被自动关闭(关闭时会自动调用finish())后,再获取完整的压缩数据:

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

    // compress
    byte[] compressed;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (InputStream is = new ByteArrayInputStream(uncompressed);
            OutputStream os = new GZIPOutputStream(baos)) {
        IOUtils.copy(is, os);
    } // try块结束后,GZIPOutputStream自动关闭,完成收尾
    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 baosDecompress = new ByteArrayOutputStream()) {
        IOUtils.copy(is, baosDecompress);
        decompressedBack = baosDecompress.toByteArray();
    }
        
    assertArrayEquals(uncompressed, decompressedBack);
}

为什么flush()不行?

flush()的作用是将输出流缓冲区中的数据立即写入底层流,但不会触发GZIP格式的收尾操作。只有finish()或close()方法才会写入GZIP所需的结束校验信息,确保压缩数据的完整性,让GZIPInputStream能够正确识别压缩流的结束位置。

内容的提问来源于stack exchange,提问作者Leszek Pachura

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:10:19