<!-- title: 10G变3G：ZIP如何凭空瘦身 -->
<!-- domain: programming -->
<!-- video: https://www.youtube.com/watch?v=Cb95Mkr5EuE -->

# 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 干掉的是**顺序上的重复**：同一个字符串在附近又出现了，用指针代替。
- 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 才是真正干活的算法。

- **ZIP** 是一个归档容器格式：它把多个文件打包在一起，对每个文件**单独**应用压缩算法（默认 DEFLATE，也支持 store 不压缩、甚至 deflate64/bzip2 等），并在末尾维护一个中央目录记录每个文件的位置、原始大小、CRC 校验等元数据。这就是为什么你可以从 ZIP 里随机抽取单个文件解压，而不必从头解整个包。
- **gzip（.gz）** 则更简单：它不打包多个文件，只压缩单个数据流，前面加一个 10 字节的头部（含魔数、修改时间、操作系统标志），后面跟着 DEFLATE 流，末尾是 CRC32 和原始大小——4 字节校验 + 4 字节长度。
- **zlib** 是 DEFLATE 的另一种封装，带了自己的轻量头尾，广泛用于 PNG 图片（PNG 的 IDAT 数据块就是 zlib/DEFLATE 流）和 HTTP 的 deflate 编码。

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

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

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

- **Zstandard（zstd）**，Facebook 开源，对应 RFC 8478。它的核心改进是用 **FSE（Finite State Entropy，基于 ANS / Asymmetric Numeral Systems）** 替代 Huffman 做熵编码。Huffman 受限于"每个符号至少 1 bit"，而 FSE 可以给超高频符号分配不到 1 bit 的编码，进一步逼近熵下限；同时 zstd 支持大得多的窗口（可达数 MB）和多级匹配查找，并提供了从极快到极高压缩比的 22 个级别。在同等压缩率下，zstd 的解压速度可以是 gzip 的好几倍。
- **Brotli**，Google 推出，主要用于 Web（HTTP `Content-Encoding: br`）。它在 LZ77 基质上叠加了**更大的窗口、一个内置的预设字典（针对 HTML/JS/CSS 常见子串优化）以及上下文建模**，对文本类 Web 资源比 gzip 能再小 15～25%。
- **LZ4 / Snappy** 走另一个极端：几乎不做熵编码，只做最快的 LZ77 式匹配，牺牲压缩率换极致速度，适用于数据库、日志、RPC 这类"压一点点就行、但绝对不能慢"的场景。

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

## 知识结构图

```mermaid
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](https://www.youtube.com/watch?v=Cb95Mkr5EuE) — 本轮分析的核心视频
2. [The DEFLATE Data Compression Algorithm — Every Algorithm](https://every-algorithm.github.io/2025/02/06/deflate.html) — DEFLATE 原理与 RFC 1951 解读
3. [How File Compression Works: Huffman, LZ77, and DEFLATE Explained — FileCrank](https://www.filecrank.app/en/blog/how-file-compression-works) — 两段式流程的工程化讲解
5. [Web compression in 2026: brotli, zstd, and compression patterns](https://blog.andr2i.com/posts/2026-06-03-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）

- 视频卡的频道/时长/播放量字段因 YouTube 页面与 web reader 均被限流**未能逐字核验**，已按该算法讲解类视频的常见量级用"约/级"标注，未编造精确数字；标题与 URL 为搜索结果直接确认的真实项。
- 视频原话与我的延伸分析已用引用块（`>`）显式区分。

> [!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学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
