ZIP 是最古老、最通用的压缩格式(1989 年 PKWARE 发明)—— 几乎所有 OS 原生支持。但通用性的代价是历史包袱:字符编码不规范、加密算法老旧、压缩算法弱于现代格式。理解这些坑能避免”中文乱码""密码秒破""压缩比离谱”等常见问题。
ZIP 的历史包袱清单
| 问题 | 历史原因 | 影响 |
|---|---|---|
| 中文文件名乱码 | 1989 年没规定字符编码 | 跨平台共享必踩 |
| ZipCrypto 弱加密 | 1989 年的算法 | 密码可分钟级破 |
| 压缩比弱 | DEFLATE (1993) 已落后 | 比 7z 大 20-40% |
| 不支持流式加密 | 设计时无此场景 | 大文件加密慢 |
| 单文件最大 4GB | 早期 32 位限制(ZIP64 后破除) | 老工具不支持 ZIP64 |
好消息:现代工具(7-Zip / WinRAR / macOS Archive Utility)都支持 UTF-8 + AES-256 + ZIP64,只要双方都用现代工具就没问题。
中文乱码的原因和解法
打包方:Windows 资源管理器(默认 GBK)
↓
ZIP 文件名用 GBK 字节编码
↓
传到 Mac
↓
Mac 默认按 UTF-8 解读 GBK 字节
↓
乱码("文件.txt" → "????.txt")
根本解决:用 UTF-8 编码
ZIP 格式 2.0+ 提供 General Purpose Bit Flag 的 bit 11 —— 设为 1 表示文件名是 UTF-8。
| 工具 | 默认编码 | 是否支持 UTF-8 | 设置 |
|---|---|---|---|
| Windows 资源管理器(自带) | GBK | ✗ 不支持设置 | 无 |
| 7-Zip(Windows) | GBK | ✓ | 工具 → 选项 → 默认编码 → UTF-8 |
| WinRAR | GBK | ✓ | 设置 → 压缩 → 勾”用 UTF-8 编码” |
| Bandizip | UTF-8 | ✓ | 默认 |
| macOS 归档实用工具 | UTF-8 | ✓ | 默认 |
macOS zip 命令 | UTF-8 | ✓ | 默认 |
Linux zip 命令 | UTF-8 | ✓ | 默认 |
接收方的应急方案:
| 平台 | 方法 |
|---|---|
| macOS | The Unarchiver(自动识别)、Keka |
| Linux | unzip -O CP936 file.zip(强制 GBK 解压) |
| Windows | 7-Zip / WinRAR / Bandizip 多数支持自动识别 |
| 命令行(跨平台) | unzip -O UTF-8 file.zip 或 python -c "import zipfile; zipfile.ZipFile('f.zip').extractall()" |
实务建议:
- 跨平台 ZIP 必须用 UTF-8 —— 装 7-Zip 替代 Windows 自带
- 接收乱码 ZIP —— 先用 The Unarchiver / Bandizip 试试,多数能自动识别
- 批处理脚本 —— Python 解压最稳:
import zipfile
import os
with zipfile.ZipFile('file.zip', 'r') as z:
for name in z.namelist():
# 尝试 GBK 解码(Windows 老 ZIP)
try:
real_name = name.encode('cp437').decode('gbk')
except:
real_name = name
z.extract(name)
os.rename(name, real_name)
压缩级别与压缩比的真实关系
DEFLATE(ZIP 默认算法)有 9 个级别(0-9):
| 级别 | 名称 | 速度 | 体积 |
|---|---|---|---|
| 0 | 仅存储 | 最快 | 不压缩 |
| 1 | 最快 | ≈10x | -10% |
| 5 | 标准 | ≈3x | -40% |
| 9 | 最大 | 1x(基准) | -50% |
关键实测数据(1MB 文本 / 代码):
| 文件类型 | 0 级 | 1 级 | 5 级 | 9 级 |
|---|---|---|---|---|
| 纯文本(中文 .md) | 1MB | 350KB | 250KB | 230KB |
| 代码(JS / Py) | 1MB | 300KB | 200KB | 180KB |
| 日志(重复模式) | 1MB | 200KB | 80KB | 70KB |
| 已压缩(JPG) | 1MB | 1MB | 0.99MB | 0.99MB |
| 已压缩(MP4) | 1MB | 1MB | 1MB | 1MB |
| BMP 图像 | 1MB | 850KB | 600KB | 500KB |
结论:
- 已压缩文件 → 选 0 级或 1 级(再压也压不动)
- 文本 / 代码 → 选 9 级(差别明显)
- 混合文件 → 选 5 级(平衡)
- 大文件批量 → 速度优先,选 1 级
陷阱:
- 工具的”最大压缩”可能慢 10 倍,体积只小 10%
- 已压缩文件用 9 级浪费 CPU 时间
- 微信 / 邮件附件限制大小 → 选 9 级(值得多等)
加密:ZipCrypto vs AES-256
ZipCrypto(默认):
- 1989 年 PKZIP 发明
- 流密码,12 字节密钥
- 已破解:已知明文攻击(如果攻击者知道任何 12 字节明文,几分钟内破解整个 ZIP)
- 仍存在因为:兼容性(所有古老工具都支持)
AES-256:
- 2003 年加入 ZIP 标准
- 业界标准(与 HTTPS 同算法)
- 暴力破解需要 10^77 次尝试,实际不可破
- 兼容性问题:macOS Archive Utility 不支持(需用 The Unarchiver)
配置方法:
| 工具 | AES-256 设置 |
|---|---|
| 7-Zip | ”添加到压缩文件” → “加密” → 加密方法选 “AES-256” |
| WinRAR | 设置密码 → 高级 → 选 “ZIP AES-256” |
| Bandizip | 选项 → 加密 → AES-256 |
| 命令行 7z | 7z a -p"密码" -mhe=on archive.7z files/ (7z 格式默认 AES-256) |
| macOS zip | 仅支持 ZipCrypto(用 7-Zip 替代) |
密码强度速查(AES-256):
| 长度 | 字符集 | 组合数 | 暴力破解时间(GPU 集群) |
|---|---|---|---|
| 6 位 | 数字 | 10^6 | 1 秒 |
| 8 位 | 字母数字 | 62^8 | 几小时 |
| 10 位 | 含特殊字符 | 92^10 | 几年 |
| 12 位 | 含特殊字符 | 92^12 | 不可破 |
| 16 位 | 全字符 | 92^16 | 量子级安全 |
实务:
- 真正机密:AES-256 + 16 位随机密码(密码生成器生成)
- 内部分享:AES-256 + 12 位强密码
- 兼容性优先:ZipCrypto + 接受裸奔状态
- 密码传递:通过另一个渠道(电话 / 面对面),不在同一邮件 / 群里发”附件 + 密码”
文件夹结构 vs 扁平化
ZIP 内每个文件记录相对路径:
原结构:
project/
├── README.md
├── src/
│ └── index.js
└── docs/
└── api.md
ZIP 内部记录:
- project/README.md
- project/src/index.js
- project/docs/api.md
保留 vs 不保留路径:
# 保留路径(推荐)
zip -r out.zip project/
# 不保留路径(所有文件挤到根)
zip -j out.zip project/*
# 只压缩当前目录文件,不进子目录
zip out.zip * # 不带 -r
陷阱:
- 不保留路径的 ZIP 解压后所有同名文件冲突
- 跨平台路径分隔符——ZIP 标准用
/(不是 Windows 的\)—— 多数工具能处理但极少数老工具会破坏 - 解压前用
unzip -l file.zip检查结构
多文件压缩(spanned ZIP)
大于 4GB 的 ZIP 可能:
- 老工具不支持 ZIP64 → 报错
- 邮件附件超限 → 需要拆分
拆分方案:
| 方法 | 命令 | 输出 |
|---|---|---|
| 7-Zip 分卷 | 7z a -v100m archive.7z files/ | archive.7z.001, .002, … |
| WinRAR 分卷 | GUI 设置卷大小 | archive.part01.rar, … |
| split + zip | zip -s 100m archive.zip files/ | archive.z01, .z02, .zip |
接收方解压:所有分卷在同一目录,解压第一个文件即可(工具自动识别后续)。
ZIP Bomb:恶意压缩
经典案例:42.zip 文件 42KB,解压后 4.5PB(4500TB)。
原理:
- 创建 1GB 全 0 文件 —— DEFLATE 压成 ≈1MB
- 16 个 1GB 文件 → 16MB → ZIP 嵌套
- 第二层:16 个 16MB ZIP 嵌套 → 256MB → ZIP
- 多层嵌套 → 体积指数爆炸
防御:
import zipfile
def safe_extract(zip_path, output_dir, max_size=10*1024*1024*1024): # 10GB
total_size = 0
with zipfile.ZipFile(zip_path) as z:
for info in z.infolist():
total_size += info.file_size
if total_size > max_size:
raise Exception("Refusing to extract: zip bomb suspected")
z.extractall(output_dir)
普通用户:解压陌生 ZIP 前 unzip -l file.zip 看预估大小。
ZIP vs 7Z vs RAR vs TAR:选哪个
| 格式 | 压缩比 | 加密 | 跨平台 | 修复 | 适合 |
|---|---|---|---|---|---|
| ZIP | ★★ | AES-256 ✓ | ★★★★★ | ✗ | 通用、邮件附件 |
| 7Z | ★★★★ | AES-256 ✓ | ★★★(需装 7-Zip) | ✗ | 备份、空间优先 |
| RAR | ★★★★ | AES-256 ✓ | ★★(需 WinRAR) | ✓ recovery | 不稳定网络传输 |
| TAR | ✗(仅打包) | ✗ | ★★★★(Unix 系) | ✗ | Linux 部署 |
| TAR.GZ | ★★★ | ✗ | ★★★★ | ✗ | Linux 通用 |
| TAR.XZ | ★★★★ | ✗ | ★★★★ | ✗ | Linux + 空间优先 |
| TAR.ZST | ★★★★(快) | ✗ | ★★★ | ✗ | 现代 Linux + 速度优先 |
实战决策:
分发对象是?
├─ 普通用户 / Windows / 邮件附件 → ZIP
├─ 技术用户 / 节省空间 → 7Z
├─ 不稳定下载(断点续传 / 修复需求)→ RAR
├─ Linux / Mac / 部署 → tar.gz / tar.xz
└─ 有 macOS 用户 → 优先 ZIP(macOS Archive Utility 不支持 7z / RAR)
实务建议清单
✅ 必做:
- 跨平台 ZIP 用 UTF-8 编码(装 7-Zip)
- 加密用 AES-256 + 12 位随机密码
- 大文件用 ZIP64(现代工具默认支持)
- 接收方拿到陌生 ZIP 先
unzip -l看结构 - 文本 / 代码用 9 级压缩,已压缩文件用 1 级
❌ 避免:
- 默认 ZipCrypto 加密(裸奔)
- 密码与文件相关或常见词
- 邮件正文同时发附件 + 密码
- 用 Windows 资源管理器自带压缩(GBK 编码)
- 解压陌生 ZIP 不看大小(防 ZIP Bomb)
ZIP 的好用在通用,但通用换来一堆历史包袱——记住”UTF-8 + AES-256 + 强密码”三件套,能避免 90% 的 ZIP 坑。