为何调用flush()再close()时Java GzipOutputStream会在尾部前写入03 00字节?
Great question—this is a common gotcha when working with Java's GZIPOutputStream and sync flushes. Let's break this down step by step to explain what those bytes are and why they show up even when you've set syncFlush=true.
What Do Those 0x00 and 0x03 Bytes Mean?
First, remember that GZIP uses the DEFLATE compression format under the hood. Those two bytes are part of DEFLATE's block structure, specifically marking the end of the compressed stream:
- DEFLATE organizes data into blocks, each starting with a 1-byte header. The
0x03byte is this header: its binary value00000011tells decoders two things: this is the final block of the stream (bit 0 is 1), and it's an uncompressed stored block (bits 1-2 are 00). - The
0x00byte right after it is the first half of the stored block's length marker. Since this is an empty block (we're ending the stream, no more data to compress), the length is 0, so we start with0x00.
If you look closely at your hexdump, you'll see the full final block is actually 0x03 0x00 0x00 0xFF 0xFF (header + 16-bit length + 16-bit length complement). The 0x00 you're noticing is just the first byte of that length field.
Why Doesn't flush() Drain All Bytes?
Even with syncFlush=true, flush() isn't designed to close the compression stream—it's only meant to force all buffered data up to that point to be written in a way that decoders can immediately process it. Here's exactly what happens in your code:
- Writing data: The DEFLATE compressor takes your string, buffers it, and compresses it into Huffman-encoded blocks.
- Calling flush(): With
syncFlush=true, this triggers a sync flush block—an empty, non-final stored block (0x00 0x00 0x00 0xFF 0xFF). This tells any decoder "you can decode everything up to here right now, no need to wait for more data." But the compressor stays open, ready to accept more input. - Calling close(): This tells the compressor to wrap things up. It writes that final empty stored block (
0x03header + length data) to mark the end of the DEFLATE stream, then adds the mandatory GZIP trailer (the CRC32 checksum and uncompressed data length).
The 0x00 and 0x03 bytes you're seeing are parts of these two blocks: the 0x00 comes from the sync flush block's length, and 0x03 is the header of the final block that close() adds.
Can I Avoid These Bytes?
Short answer: Not if you need to use flush() with syncFlush=true before closing. The DEFLATE format requires a clear end-of-stream marker, which can only be written when you call close(). flush() is for intermediate flushes, not terminating the stream.
If you didn't need intermediate flushes, you could skip calling flush() entirely (since close() automatically flushes all buffered data), but that doesn't fit your use case. For scenarios where you need to force flushes mid-stream and then close, these extra bytes are an expected part of how DEFLATE and GZIP work.
内容的提问来源于stack exchange,提问作者Snakienn

