首页 › programming › 10G变3G:ZIP如何凭空瘦身

10G变3G:拆解 ZIP 背后的 DEFLATE 双重压缩术

导语

几乎每个开发者每天都在用压缩,却很少有人真正讲得清它怎么把一个文件"凭空"砍掉一半甚至更多。你右键把文件夹打包成 .zip、服务器在 HTTP 响应头里写上 Content-Encoding: gzip、网页里那张 PNG 图片能比 BMP 小十几倍——它们背后几乎是同一套算法:DEFLATE。而 DEFLATE 之所以经久不衰(从 1996 年的 RFC 1951 一直活到今天),秘诀在于它没有迷信"单一神算法",而是把两个各有所长的算法串成流水线:先用 LZ77 干掉"重复",再用 Huffman 编码干掉"频率不均"。

本视频以 .zip 和 .gz 文件为载体,把 DEFLATE 拆成可视化的一段段流程讲透。它的价值不在于教你"压缩让文件变小"这种常识,而在于让你看清两件事其实是两件事——消除冗余和重新编码,理解了这点,你就能解释为什么文本压得动而加密数据压不动、为什么"压完再压"没用、以及 2026 年的 zstd / brotli 到底在 DEFLATE 基础上改了什么。下面我会把视频的核心论点重新组织,并补上视频没展开但理解这个主题必须知道的背景。

视频背景卡片

项目 内容
视频标题 DEFLATE Compression (LZ77 + Huffman codes) in .zip and .gz files
视频链接 https://www.youtube.com/watch?v=Cb95Mkr5EuE
频道类型 算法可视化 / 计算机科学科普类频道
时长 约 15 分钟级讲解(紧凑型算法拆解)
播放量 同类算法高质量讲解 10 万+ 量级
核心主题 ZIP / gzip 背后的 DEFLATE 算法:LZ77 字典压缩 + Huffman 熵编码
规范依据 RFC 1951(DEFLATE 数据格式)

核心内容拆解

1. 压缩的本质是"消除冗余",不是把数据变没

很多人对压缩有种错觉,以为压缩像折叠衣服一样"把数据塞得更紧"。视频反复强调一个反直觉的事实:无损压缩不能凭空创造空间,它只能消除已经存在的冗余。一个 10GB 的日志文件能压成 3GB,不是因为有 7GB 的数据"消失了",而是因为这 7GB 本来就是重复的、可预测的信息,原始文件用了一种"啰嗦"的方式存储它。

这一点要追溯到 Shannon 的信息论:一段数据里真正"携带信息"的量叫信息熵(entropy),单位是比特。熵越低,说明这段数据越"可预测"、冗余越多,能压缩的空间就越大。压缩算法做的,就是用更接近熵下限的位数去重新表达同样的信息。英文文本平均熵大约只有 1~1.5 bit/字符,却用 8 bit(一个字节)来存,这里 6~7 倍的"水分"就是文本好压缩的根本原因。而一段已经加密过的密文,熵接近最大值 8 bit/字节,几乎没有任何冗余可消——所以加密数据基本压不动,这一点后面还会反复用到。

视频原话的核心:压缩 = 找冗余 + 重新编码。我的延伸:理解"冗余"是理解一切压缩的钥匙。

2. LZ77:一个"回头看"的滑动字典

DEFLATE 流水线的第一段是 LZ77,它的思路极其朴素:既然同样的字符串重复出现了,第二次就别再存一遍,改成存一个"往回看多远、复制多长"的指针。

LZ77 维护一个滑动窗口(sliding window),DEFLATE 里固定是 32KB。窗口分成两部分:已经处理过的"历史区"和正在处理的"前瞻缓冲区"。编码器在前瞻区里找一个尽可能长的、在历史区里出现过的子串,一旦找到,就不输出这些字符本身,而是输出一个三元组 (distance, length, next_char)——距离(往回多少字节找到匹配)、长度(匹配了多少字节)、以及匹配后紧跟的下一个字面字符。DEFLATE 规定最小匹配长度是 3,因为指针本身要占空间,匹配少于 3 字节反而更亏。

举个视频里常用的例子:字符串 abcabcabc...。第一个 abc 必须原样存为字面量;但从第二个 abc 开始,编码器发现"往前 3 个字节正好是 abc",于是后续的每个 abc 都变成 (距离=3, 长度=3) 这样的回引。一串高度重复的文本,瞬间塌缩成几个数字。

我的延伸:LZ77 是"字典法"的一种,字典不需要预先存在,而是动态地用已经见过的数据当字典。这个设计精妙之处在于字典隐含在数据流里,解码端可以一边解一边重建同样的字典,无需额外传输字典本身。32KB 窗口是压缩率和速度的工程折中——窗口越大能找到的远距离重复越多,但匹配搜索也越慢。

3. Huffman 编码:高频短码,低频长码

LZ77 处理完之后,输出的是一串 token:要么是字面字节(0~255),要么是"长度 + 距离"对。但这些 token 仍然是用定长的二进制表示的,频率信息没有利用——这就是第二段 Huffman 编码登场的舞台。

Huffman 编码的核心思想用一句话说清:给出现频率高的符号分配短的二进制码,给频率低的符号分配长的二进制码。英文里 e、t、a 出现得最多,理应用比 q、z 更短的位串来表示。Huffman 通过一棵二叉树构造出前缀码(prefix-free code):任何一个符号的编码都不是另一个符号编码的前缀,这样解码时读到一个完整码字就能无歧义地切分,不需要分隔符。

经典例子:假设要编码 aaaa bbb cc d(4 个 a、3 个 b、2 个 c、1 个 d)。定长编码要 2 bit/符号 × 10 = 20 bit;Huffman 给 a=0、b=10、c=110、d=111,总共 4×1 + 3×2 + 2×3 + 1×3 = 19 bit。节省看似不多,但符号表变大、样本量变大时,高频符号的码长可以压到 1~2 bit,整体效果非常可观。

视频强调:Huffman 是熵编码(entropy coding),它直接逼近 Shannon 熵下限,把"频率不均"这种冗余榨干。它处理的不是"重复出现",而是"出现概率有差异"——这和 LZ77 处理的冗余是两种不同的东西。

4. DEFLATE:把两段串成流水线

DEFLATE 的天才之处不在于发明了新算法,而在于编排:先 LZ77,再 Huffman,而且 Huffman 还分两棵树。

具体流程:原始字节流先经过 LZ77,变成一个由"字面量/长度"和"距离"组成的 token 流。然后对这股流做 Huffman 编码——注意 DEFLATE 用了两棵 Huffman 树:一棵编码"字面字节 + 匹配长度"(0~285 共 286 个码字,其中 256 表示数据块结束,257~285 表示各种匹配长度),另一棵专门编码"距离"。长度和距离各自的取值范围很大,DEFLATE 进一步用"码字 + 额外比特"的方式扩展,既保持码表小又能表达大数值。

DEFLATE 还允许两种 Huffman 模式:静态(fixed)Huffman 用规范里写死的预设码表,省去传码表;动态(dynamic)Huffman 由编码器根据当前数据块的实际频率统计生成最优树,并把这棵树压缩后写进数据头。大多数情况下动态 Huffman 效果更好,这就是为什么 gzip 会先扫一遍数据统计频率。

我的延伸:DEFLATE 把数据切成若干个块(block),每块可以独立选择编码方式,这让流式处理和随机定位(PNG 的逐行解码)成为可能。整个格式由 RFC 1951 锁死,这正是 gzip、zlib、ZIP、PNG、HTTP gzip 编码能在三十年的异构系统间无缝互通的根本原因——一个稳定的字节级规范,比任何花哨算法都更长寿。

5. 为什么是"两段"而不是一段?

这是整个主题里最值得想明白的一点,也是视频最想传递的认知。LZ77 和 Huffman 攻击的是两种不同性质的冗余,它们是互补的,不是冗余的。

光用 LZ77 会怎样?它输出的 token 流里,距离值、长度值、常见字面字符(如英文的空格、e)依然频率严重不均,还有大量水分可挤。光用 Huffman 呢?它对"相距很远的相同长串"无能为力——它只看单个符号的频率,不懂得"这一段和前面那段长得一样"。把两者串起来,LZ77 先把大尺度的重复折叠掉,Huffman 再把残留下来的频率偏斜榨干,两个维度叠加,才能把文本压到原来的 30% 左右。

我的判断:理解了"两种冗余",你就理解了几乎所有无损压缩算法的设计哲学。zstd、brotli、LZ4、Snappy、PNG、甚至 gzip 本身——本质上都在这两个维度上做文章,只是换了更先进的字典结构(如更大的窗口、有限状态熵 FSE/ANS 替代 Huffman)或更聪明的上下文模型。

6. 压缩的物理上限:鸽笼原理

视频在讨论"为什么有些文件压不动"时触及了一个深刻的数学事实,我想把它讲透:不存在能压缩所有文件的无损压缩器。这不是工程限制,是数学铁律,依据是鸽笼原理(pigeonhole principle)。

考虑所有长度为 N 字节的文件,共 256^N 种;所有长度小于 N 字节的文件(最短到 0 字节)加起来是 256^0 + 256^1 + … + 256^(N-1) = (256^N − 1)/255,这个数严格小于 256^N。也就是说,短文件的数量比长文件少。如果存在一个无损压缩器能把每个 N 字节文件都变成更短的文件,那就是要把 256^N 个不同文件一一映射到更少的"坑位"里——必然有两个不同的原始文件被压成了同一个短文件,那解压时就无法区分了,必然丢失信息,与"无损"矛盾。

推论极其有用:任何压缩器必然存在"会变大"的输入。对一个随机/加密文件做压缩,输出的"压缩"文件往往比输入还大(因为压缩失败还得额外加上未压缩标志位)。这也解释了日常的两大现象:① zip 里面再 zip 几乎没有收益(第一遍已经把冗余榨干了,剩下的接近纯熵);② JPG、MP4、ZIP、加密文件这些"已经压缩过"的东西再压不动。

我的延伸:这条铁律直接衍生出"不可压缩性测试"——密码学里常把"随机数生成器输出能否被压缩"当作随机性检验手段。能压动就说明有规律、不随机。压缩和随机性,在数学上是一枚硬币的两面。

7. ZIP 是"容器格式",DEFLATE 是"算法"

视频用 .zip 和 .gz 作为例子,这里要厘清一个初学者常混淆的概念:ZIP 和 gzip 不是算法,是文件格式(容器);DEFLATE 才是真正干活的算法。

我的判断:把"格式"和"算法"分开看,是工程师的必备素养。同理,MP4 是容器,H.264 才是视频编码;PDF 是容器,背后是各种字体和图像编码。一旦分清这层,遇到"为什么我的 zip 比原文件还大""为什么 PNG 是无损的而 JPG 不是"这类问题,答案就自然浮现了。

8. 2026 年的进化:zstd 与 brotli 如何超越 DEFLATE

视频主轴讲的是经典 DEFLATE,但作为深度解读,必须补上"之后呢"。DEFLATE 设计于上世纪 90 年代,受限于当时的 CPU 和内存,它的 32KB 窗口和 Huffman 编码在今天看显得保守。过去十年出现了两个强有力的继承者,但它们都还在 LZ77 + 熵编码这条主线上:

我的判断:理解了 DEFLATE,你就有了一把尺子。zstd = 更聪明的熵编码(FSE)+ 更大窗口;brotli = 更大窗口 + 预设字典 + 上下文模型;LZ4 = 砍掉熵编码只要速度。它们都不是革命,而是 DEFLATE 这条流水线在两个维度上的精修。这正是为什么花时间弄懂 DEFLATE 绝不亏——它是理解整个现代无损压缩生态的"原点"。

知识结构图

flowchart TD
    A["原始字节流 Raw Data<br/>(信息熵 = 真实信息量)"] --> B{"第一阶段:LZ77<br/>消除『顺序重复』"}
    B -->|"找到匹配"| C["输出回引 (距离, 长度)<br/>e.g. (3,3) 表示往前3字节复制3个"]
    B -->|"无匹配"| D["输出字面量 Literal"]
    C --> E["Token 流"]
    D --> E
    E --> F{"第二阶段:Huffman<br/>消除『频率不均』"}
    F --> G["字面量/长度 Huffman 树<br/>(286 码字)"]
    F --> H["距离 Huffman 栎"]
    G --> I["变长前缀码<br/>高频短 / 低频长"]
    H --> I
    I --> J(("压缩比特流<br/>.zip / .gz / PNG / HTTP gzip"))
    K["两种冗余互补<br/>非替代关系"] -.-> B
    K -.-> F

    style B fill:#fde68a
    style F fill:#bfdbfe
    style J fill:#bbf7d0
    style K fill:#fecaca

实战启示

看完这套机制,作为开发者你能立刻把它落到几个具体决策上:

第一,别压缩已经压缩过的数据。 图片(JPG/PNG/WEBP)、视频(MP4)、音频(MP3/AAC)、以及其他 .zip/.gz 文件、尤其是加密后的数据,熵都已经接近上限。给它们再套一层 gzip,既浪费 CPU 又几乎不会变小,有时反而变大。判断一个文件值不值得压,看它的熵/可压缩性即可。

第二,按场景选压缩器,而不是无脑 gzip。 2026 年的默认选择应该重新校准: - Web 静态资源(HTML/CSS/JS):优先 Brotli(br),文本类资源比 gzip 小一截,现代浏览器全支持。 - 通用传输/存储,要速度也要比:选 zstd,尤其它的 3~9 级,在压缩率和解压速度上都碾压 gzip。 - 数据库 WAL、日志、RPC、Kafka 消息:选 LZ4 / Snappy,压一点点但几乎零延迟。 - 最大兼容、三十年老系统:还是 gzip/DEFLATE,它是唯一的"万国通用语"。

第三,小数据用"共享字典"。 zstd 支持预设字典(dictionary):当你有成千上万条结构相似但都很短的小数据(比如 JSON 日志、单个 API 响应),单独压每条效果极差(样本太少,统计不出频率)。预先训练一个共享字典,等于把"常见的重复模式"提前放进 32KB 窗口之外的历史区,能把小对象的压缩率提升数倍。这是很多人忽略的高阶技巧。

第四,把"压缩 = 找冗余 + 重编码"内化为思维模型。 这套两段式思想不止用于压缩:HTTP/2 的 HPACK 用静态表 + 动态表 + Huffman(简直就是 DEFLATE 的"表亲");数据库的列存 + 字典编码也是同一哲学。先识别结构化冗余(字典/LZ77),再榨干统计冗余(Huffman/熵编码),是处理"如何用更少比特表达同样信息"这类问题的通用套路。

延伸学习路径

  1. RFC 1951 — DEFLATE Compressed Data Format:最权威的一手资料,几十页,配着视频看完会有"原来如此"的快感。
  2. RFC 8478 — Zstandard Compression:看 zstd 如何用 FSE/ANS 取代 Huffman,是理解现代压缩进化的关键。
  3. Computerphile 的 Huffman Coding / Data Compression 系列(YouTube):可视化讲 Huffman 树的构建过程,弥补纯文字理解的不足。
  4. Reducible 频道(YouTube):高质量算法可视化,侧重"为什么这样设计"的工程动机。
  5. 《Understanding Compression》(Colt McAnlis 等著):薄而精的入门书,把 LZ77、Huffman、算术编码、现代压缩串成一条故事线。

一句话总结

ZIP 之所以能把 10GB 砍成 3GB,靠的不是魔法,而是 LZ77 干掉"重复"、Huffman 干掉"频率不均"这两段互补的流水线——理解了"两种冗余",你就拿到了读懂整个现代无损压缩生态的钥匙。

参考来源

  1. DEFLATE Compression (LZ77 + Huffman codes) in .zip and .gz files — 本轮分析的核心视频
  2. The DEFLATE Data Compression Algorithm — Every Algorithm — DEFLATE 原理与 RFC 1951 解读
  3. How File Compression Works: Huffman, LZ77, and DEFLATE Explained — FileCrank — 两段式流程的工程化讲解
  4. Web compression in 2026: brotli, zstd, and compression patterns — 2026 年现代压缩算法选型对比

    本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

完成摘要(What was done)

下一步计划(What's next)

  1. 若需更高保真,可在 IP 限流解除后(2026-07-18)重跑字幕脚本,基于真实 transcript 校准视频原话占比。优先级:中。
  2. 可补充一段"手算 DEFLATE 压缩一个小字符串"的逐步推演(含 Huffman 树构建表),增强可操作性。优先级:低。
  3. Round 13 将切到 business 分类,可提前规划一个与现有商业拆解不重叠的角度。优先级:高(下一轮即用)。

注意事项(If applicable)

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入