开始
让我们制作一个gzip压缩文件,看看里面有什么。我们将保持大略:只需将8个字符串“aaaaaaaa”写入到文件。
echo "aaaaaaaa" >hello.out
用xxd查看二进制内容:
xxd hello.out0000000: 6161 6161 6161 6161 0a aaaaaaaa.
如上所示,文件有9字节长。8个字节的“aaaaaaaa”,结尾写入了一个换行(LF)字符。

用gzip对其压缩。我们选用gzip -1,这是最快的压缩模式。gzip命令的详细利用方法不再赘述,基本命令参数如下:
gzip -1 hello.out
连续用xxd查看二进制内容:
xxd hello.out.gz0000000: 1f8b 0808 9494 a061 0403 6865 6c6c 6f2e ....'..a..hello.0000010: 6f75 7400 4b4c 8400 2e00 b666 d7ad 0900 out.KL.....f....0000020: 0000
内容剖析:
前几个字节非常大略:
1f8b:是gzip文档格式,硬编码的gzip标头。
08:表示DEFLATE压缩方法。
08(00001000):位3被设置,所以是一个文件名。
9494 a061:2021-11-26日星期五16:28:12。
04,表示压缩是利用最快的算法(-1标志的)。
03,Unix操作系统(LF/CLRF)。
接下来的几个字节对应的是文件名: 。
6865 6c6c 6f2e 6f75 74 00h e l l o . o u t NUL
压缩数据
数据从字节0x13开始,以4b开头的为压缩的数据要解码,须要查看各个位,由于DEFLATE将信息打包成可以超过字节边界的位。具有5位或9位代码的情形并不少见。
xxd -s 21 -b test.out.gz0000013: 00000000 01001011 01001100 10000100 00000000 00101110 .KL...0000019: 00000000 10110110 01100110 11010111 10101101 00001001 ..f...000001f: 00000000 00000000 00000000
接着来分解一下。xxd 将字节一个一个地打印出来,其顺序为MSB到LSB。但是在gzip 中,字节被打包是LSB到MSB顺序的。以是必须逐字节反转字符串。
解码块8bitswise: 11010010 00110010 00100001 00000000 01110100 00000000转化后: 1 10 10010001 10010001 0000100 00000 00111010 0000000 00
用固定的霍夫曼代码压缩(不要忘却,虽然比特流说“10”,但它被读为01,由于数据文本将以小端格式阐明)
接下来解码霍夫曼码。固定霍夫曼码(别号静态霍夫曼码)的要点是它们是一堆经由商定的霍夫曼码,长度范围为7-9位。与所有霍夫曼代码一样,每个代码都是无前缀的,这意味着当一点一点地读取比特流时,每个代码何时结束都无任何歧义。
霍夫曼表规范中:
Lit Value Bits Codes--------- ---- -----0 - 143 8 00110000 through10111111144 - 255 9 110010000 through111111111256 - 279 7 0000000 through0010111280 - 287 8 11000000 through11000111
要解码霍夫曼码,必须(可能)读取接下来的9位。从一点一点地读取比特流开始,直到识别出一个唯一标识它是哪个字符的前缀。可以从观点年夜将其视为沿着霍夫曼树的边缘遍历下去。
接下来的9位是100100011-其前缀100,它表示这是0-143之间的文本。以是它只有8位 (1001 0001)。
霍夫曼代码将LSB打包为MSB,但将被阐明为大端格式的整数。解码得到:
val = (10010001 - 00110000)=145-48=97。
97是'a'ASCII码。 解码别的各字节得到:
1 10 10010001 10010001 0000100 00000 00111010 0000000 0097 97 260 0 58 256 -'a' 'a' repeat 6x 1 behind 0x10 (LF) HALT <padding>LIT LIT LEN DIST LIT
有8'a',两个’aa\后跟 6 'a'重复,然后是LF。
“repeat 6x, 1 behind”是一个长度+间隔(LEN,DIST)的代码它见告解码器要重复的字符是它刚刚解码的前一个字符。在这种情形下它是“a”。
已经将8 'a's 和 LF(最初是72 位)编码为46位和2个添补位。
校验和及大小让我们完成gzip文件。接下来一个CRC32。看到带有换行符的未压缩 8 'a 将天生:ad d7 66 b6.十六进制流:
xxd hello.out.gz0000000: 1f8b 0808 27a5 a061 0403 6865 6c6c 6f2e ....'..a..hello.0000010: 6f75 7400 4b4c 8400 2e00 b666 d7ad 0900 out.KL.....f....0000020: 0000 ^^^^^^^^^^
可以清楚地看到 b6 66 d7 ad, 以小端字节顺序。为crc校验和。
接下来的4个字节09 00 00 00是9个字节的小端字节序。事实上,解码了9个字节,输入文件中有9个字节。
总结全体压缩文件剖析如下:
gzip info: 1f8b 0808 27a5 a061 0403filename: 7465 7374 2e6f 7574 00DEFLATE data: 4b 4c 84 00 2e 00crc32: b6 66 d7 adsize: 09 00 00 00
以上我们通过对gzip二进制内容解析剖析其详细编码过程,通过这样剖析来让我们理解压缩和文件编码,当然gzip最主要的动态霍夫曼算法,干系内容感兴趣的同学可以自己去学习,也可以参考gzip源码学习详细代码实现过程,这便是后话了。