gzip 是 Linux 下最常用的压缩工具之一,但很多人只知道 gzip file 这一条命令。最近在处理服务器日志压缩时,深入研究了一下它的实现原理,顺便整理成这篇文章。
gzip 的核心:DEFLATE 算法
gzip 使用的是 DEFLATE 算法,这个算法其实是两个算法的组合:
- LZ77:找出重复内容,用指针替换
- Huffman 编码:根据字符频率重新编码
LZ77 的直观理解
假设有这样一段文本:
hello hello hello world
LZ77 会发现 "hello " 重复出现了三次,第二次和第三次可以用"距离+长度"的指针表示:
hello <12,6> <18,6> world
<12,6>表示:往前数 12 个字符,复制 6 个字符- 实际存储时,指针比原始文本短很多
Huffman 编码的原理
LZ77 处理完重复后,还有个问题:有些字符出现频率高,有些低。Huffman 编码让高频字符用短编码,低频字符用长编码。
举个简单例子:
原始文本: aabacd
统计频率:a(3次), b(1次), c(1次), d(1次)
Huffman 编码后:
a→0(1位)b→100(3位)c→101(3位)d→110(3位)
编码后总长度:3×1 + 1×3 + 1×3 + 1×3 = 12 位,比固定编码的 6×8 = 48 位节省了 75%。
压缩级别的权衡
gzip 提供 9 个压缩级别(-1 到 -9),很多人有个误区:级别越高压缩比越大。这没错,但忽略了关键点:压缩时间。
我用一个 100MB 的日志文件测试了一下:
bash
# 最快压缩(level 1)
time gzip -1 large.log
# 压缩后: 28MB, 耗时: 1.2s
# 默认压缩(level 6)
time gzip -6 large.log
# 压缩后: 22MB, 耗时: 3.5s
# 最佳压缩(level 9)
time gzip -9 large.log
# 压缩后: 21MB, 耗时: 8.7s
从 level 6 到 level 9,压缩时间增加了 150%,但压缩比只提升了 4.5%。这个 trade-off 是否值得,取决于你的场景:
- 备份压缩:选 level 9,反正后台跑,不在意时间
- 实时日志:选 level 1-3,避免阻塞 I/O
- 网络传输:选 level 6(默认),平衡点
实战技巧
1. 批量压缩保持目录结构
bash
# 错误:会丢失目录结构
gzip -r /var/log/*.log
# 正确:用 find + tar
find /var/log -name "*.log" -type f | tar -czf logs.tar.gz -T -
2. 原地解压再压缩
有时候需要修改压缩文件内容:
bash
# 方法一:管道链
gunzip -c file.gz | sed 's/old/new/g' | gzip > new_file.gz
# 方法二:zcat 更直观
zcat file.gz | sed 's/old/new/g' | gzip > new_file.gz
3. 查看压缩文件内容不解压
bash
# 查看压缩文件前 10 行
zcat file.gz | head -10
# 搜索压缩文件内容
zgrep "error" file.gz
# 统计压缩文件行数
zcat file.gz | wc -l
4. 压缩时排除某些文件
bash
# 压缩目录但排除 .log 文件
tar --exclude='*.log' -czf backup.tar.gz /path/to/dir
# 排除多个类型
tar --exclude='*.log' --exclude='*.tmp' -czf backup.tar.gz /path/to/dir
与其他压缩工具对比
我在同一文件上对比了主流压缩工具:
bash
# 测试文件: 100MB 文本文件
gzip -9 test.txt # 21MB, 8.7s
bzip2 -9 test.txt # 18MB, 45s
xz -9 test.txt # 16MB, 120s
lz4 -9 test.txt # 24MB, 0.3s
zstd -9 test.txt # 17MB, 1.8s
结论:
| 工具 | 压缩比 | 速度 | 适用场景 |
|---|---|---|---|
| gzip | 中 | 中 | 通用场景,兼容性最好 |
| bzip2 | 好 | 慢 | 归档存储,不太推荐 |
| xz | 最好 | 最慢 | 长期存储,如软件包分发 |
| lz4 | 差 | 最快 | 实时压缩,日志传输 |
| zstd | 好 | 快 | 现代首选,逐渐替代 gzip |
zstd 是 Facebook 开源的压缩算法,在压缩比和速度上都有优势,但 gzip 的兼容性无可替代------几乎所有 Unix 系统都预装 gzip。
一个常见的坑
压缩后的文件,原文件会被删除:
bash
$ gzip file.txt
$ ls
file.txt.gz # 原文件没了!
解决方法:
bash
# 保留原文件
gzip -k file.txt
# 或者用输出重定向
gzip -c file.txt > file.txt.gz
性能优化:并行压缩
gzip 是单线程的,大文件压缩时 CPU 利用率只有一个核。用 pigz 可以并行压缩:
bash
# 安装
apt install pigz # Debian/Ubuntu
yum install pigz # CentOS
# 使用(自动使用所有 CPU 核心)
pigz -9 large_file
# 指定线程数
pigz -9 -p 4 large_file # 使用 4 个线程
pigz 产出的文件完全兼容 gzip,解压时用 gzip 或 pigz 都行。
小结
gzip 看似简单,但用好需要理解几个要点:
- 压缩级别:不是越高越好,根据场景选择
- 工具选择:实时场景用 lz4,归档场景用 zstd,兼容性需求用 gzip
- 并行优化:大文件用 pigz 替代 gzip
- 常见陷阱 :默认会删除原文件,记得加
-k参数
理解 DEFLATE 算法,能帮你更好地判断哪些数据适合压缩------重复度高、模式明显的数据压缩比高,已经压缩过的文件(如图片、视频)再压缩几乎无效。
相关工具:Linux tar 归档命令 | 文件哈希计算