为什么 Mac 上 ZIP 文件名会乱码,以及「编码覆盖」实际在做什么
从旧版 Windows 工具发出的 ZIP,在 macOS 上一打开文件夹名就花了。归档实用工具默认按 UTF-8 理解。ZIP 格式历史上并不强制可靠的文件名字符集字段,读取端只能猜。
歧义从哪来
Windows 上不少通用压缩工具会把非 ASCII 文件名写进区域代码页(例如 GBK、Shift-JIS),又没有现代 Mac API 能当成 UTF-8 的标志。一旦用错码表解码,已经错的字符串救不回原始字节——需要重新打开压缩包。
先检测、预览,再解压
Better UnArchiver 把编码放进「先检查」:
- 从中央目录头读取原始文件名字节。
- 尝试候选编码(含 GBK、Big5、Shift-JIS、EUC-KR)并给出预览。
- 自动选择不对时允许手动覆盖。
- 再用选定映射解压。
# 示意:按替换字符多少给候选编码打分
from collections import Counter
CANDIDATES = ["utf-8", "gbk", "big5", "shift_jis", "euc_kr"]
def preview(raw: bytes) -> list[tuple[str, str, int]]:
rows = []
for enc in CANDIDATES:
try:
text = raw.decode(enc)
except UnicodeDecodeError:
continue
bad = text.count("\ufffd") + sum(1 for ch in text if ord(ch) < 32)
rows.append((enc, text, bad))
return sorted(rows, key=lambda r: r[2])
正式实现还要处理已声明的 UTF-8 位、AppleDouble 噪声,以及试图路径穿越的条目。这些检查都在写入磁盘之前。
解决不了什么
- 在错误解码后重新保存过的 ZIP,原始字节可能已丢失。
- 不创建 RAR,也不修 RAR 恢复记录;当前版本 RAR 仅解压。
- 编码覆盖不能神奇修复 CRC 失败的内容;挽救会把可读条目写入新归档。
相关链接
- 产品:Better UnArchiver
- 场景:ZIP 文件名乱码