ZIP 文件名乱码的原因与修复方法 - Shift_JIS 与 UTF-8
结论:乱码源于双方对文件名编码的理解不一致
打开 ZIP 时,如果只有日文文件名变成“Ä╩É^âè”或“蜀咏悄繝ェ”这样的字符串,原因在于制作压缩包的程序和打开它的程序对文件名编码的理解不一致。里面的数据并没有损坏,只要用正确的编码重新读取,名字就能恢复原样。
在 ZIP 规范 APPNOTE.TXT(PKWARE,6.3.10,2022 年 11 月修订)里,每个文件头中的通用标志位(general purpose bit flag)里,能表明文件名编码的只有第 11 位(Language encoding flag,简称 EFS)。该位置 1 时,文件名必须是 UTF-8。这个标志是 2006 年 9 月的 6.3.0 版加入的。
第 11 位未置 1 时,规范要求文件名遵循“ZIP 原有的字符编码”,也就是 IBM 的 Code Page 437(CP437,见附录 D)。CP437 是 20 世纪 80 年代 IBM PC 的西文字符表,根本没有日文字符。日文文件名的 ZIP 之所以仍被大量制作出来,是因为许多软件不设这个标志,直接把所在电脑的编码字节(日文版 Windows 上是 Shift_JIS 系的 cp932)写进文件名字段。打开的一方面对没有标志的文件名,只能猜测其编码,猜错就会出现乱码。
修复办法分为三种:在打开的工具里重新选择文件名编码;重新生成修正了文件名的 ZIP;在制作时设置 UTF-8 标志或只用英文数字命名。下面先从如何辨认乱码讲起。
Windows 与 macOS 写文件名的方式不同
根据 Microsoft 的资料《Code Page Identifiers》,日文版 Windows 使用 cp932(代码页 932,表中名称为 shift_jis)。Python 的 zipfile 文档也注明,有些旧的实现会用“当前区域设置的编码或代码页”写文件名,这种情况主要出现在 Windows 上。
macOS 又如何?2026 年 10 月在 macOS 26.5 上实测,系统自带的 ditto 命令和 zip 命令(Info-ZIP 的 Zip 3.0)都把“写真リスト.txt”这个日文文件名写成 UTF-8 字节,却没有把第 11 位置 1。结果就是文件名明明是 UTF-8,却没有任何标记说明这一点。
日文文件名的写法(2026 年 10 月核实):
- macOS 26.5 的 ditto:文件名为 UTF-8,第 11 位未置 1
- macOS 26.5 的 zip(Zip 3.0):文件名为 UTF-8,第 11 位未置 1
- Python 3.14 的 zipfile:文件名为 UTF-8,第 11 位置 1
- Windows 上的旧软件(据 Python 文档的注释):文件名为所在电脑的代码页(日文为 cp932),第 11 位未置 1
从上面的列表可以看出乱码的两个典型方向:Windows 上做的 cp932 压缩包,用默认 UTF-8 的工具打开会乱码;Mac 上做的无标志 UTF-8 压缩包,用默认 cp932 的工具打开也会乱码。不过,打开一方如果猜得聪明,就不会出问题。在同一台 Mac 上用 ditto 解压 cp932 文件名的 ZIP,得到的仍是正确的“写真リスト.txt”(在日文环境下确认)。会不会乱码,取决于制作工具与打开工具的组合。
Linux 的情况也一样。Debian 的 unzip 手册(trixie)提醒,含 8 位字符的文件名,因不同工具和平台使用的编码不同,可能无法在系统之间通用。
从乱码的样子判断原因
看乱码的字形,就能知道是哪种编码被误读成了哪种。下面用 Python 3.14 重现了“写真リスト.txt”被三种方式误读的结果。
| 看到的文件名 | 实际编码 | 被误读成 |
|---|---|---|
Ä╩É^âèâXâg.txt | Shift_JIS(cp932) | CP437 |
蜀咏悄繝ェ繧ケ繝�.txt | UTF-8 | Shift_JIS(cp932) |
�ʐ^���X�g.txt | Shift_JIS(cp932) | UTF-8 |
- 带重音的西文字母和制表符(Ä、É、╩ 等):Shift_JIS 文件名按规范默认的 CP437 读取。像 Python 的 zipfile 这样严格遵循规范的工具常会这样显示
- 陌生的汉字夹杂半角片假名(“繝”“縺”格外显眼):UTF-8 文件名按 Shift_JIS 读取。Mac 上做的无标志 UTF-8 压缩包,用默认 cp932 的工具打开就是这样。UTF-8 中的平假名和片假名都是以 E3 开头的 3 字节序列,按 Shift_JIS 读取时,“繝”“縺”之类的同一个字会反复出现
- 大量替换字符(�):Shift_JIS 文件名按 UTF-8 读取,不符合 UTF-8 规则的字节被丢弃。这种形态有时无法还原,最稳妥的做法是在解压前就在工具里重新选择编码
如果在乱码状态下直接解压,文件就会以乱码的名字保存。与其解压后再逐个改名,不如用正确的编码重新打开原来的 ZIP,既快又不会遗漏。
修复方法:重新选择文件名编码再打开
最省事的办法,是用能选择文件名编码的工具重新打开。piclab 的ZIP 解压工具会自动判断 ZIP 中日文文件名的编码;如果仍有乱码,可以在“文件名编码”里改选 Shift_JIS、GBK 等。选中文件后保存,就能得到修正了文件名的 ZIP。所有处理都在浏览器内完成,文件不会被发送到外部。
电脑上装有 Python 3.11 或更高版本的话,用标准的 zipfile 命令也能修复。根据 Python 文档,--metadata-encoding 是 3.11 新增的选项,用来指定读取无标志文件名时采用的编码(对已置标志的文件名无效,以 UTF-8 为准)。
python3 -m zipfile --metadata-encoding cp932 -l archive.zip
python3 -m zipfile --metadata-encoding cp932 -e archive.zip out/第一行列出内容,确认文件名显示正常;第二行解压到 out/。2026 年 10 月,用 Python 3.14 测试一个以 cp932 文件名制作的 ZIP:不加选项时 -l 显示为 Ä╩É^âèâXâg.txt,指定 cp932 后显示为“写真リスト.txt”。如果出现乱码的是 Mac 上做的 UTF-8 压缩包,就把 cp932 换成 utf-8。
中文的 ZIP 选 gbk,韩文的 ZIP 选 cp949,也就是选择制作它的系统所用的编码。拿不准时,可参考“从乱码的样子判断原因”一节的表。关于这种编码本身的来历,请看术语表中的 Shift_JIS 词条。
制作时的预防:设置 UTF-8 标志或用英文数字命名
给不清楚对方环境的人制作 ZIP 时,用明确的方式写文件名,能省去对方很多麻烦。
- 设置 UTF-8 标志:Python 的 zipfile 会把含非 ASCII 字符的文件名自动写成 UTF-8,并把第 11 位置 1(文档说明与 2026 年 10 月的实测一致)。用
python3 -m zipfile -c archive.zip 写真リスト.txt生成的 ZIP 带有该标志。有了标志,遵循规范的工具就会直接按 UTF-8 读取,无需猜测 - 只用英文数字命名:像
photo-2026-10-01.jpg这样只用 ASCII 范围内的字符命名,无论按哪种编码读取,字节都相同,不会乱码。日期加编号的命名方式在排序时也更整齐 - 从 Mac 发给 Windows 用户前先试开:如“Windows 与 macOS 写文件名的方式不同”一节的列表所示,macOS 的标准工具写的是无标志的 UTF-8。发送前,先在与对方相同的环境下试开一次,或者先把文件名改成英文数字再压缩
发送前要把一批照片的文件名统一改成英文数字,可以参考批量重命名图片文件中的步骤。在手机上接收带密码 ZIP 时的注意事项,整理在用手机打开带密码的 ZIP一文中。
常见问题:为什么 7z 和 RAR 不容易乱码
7z 和 RAR 也会出现文件名乱码吗?很少。7-Zip 把 Unicode 文件名列为 7z 格式的特点之一;RARLAB 发布的 RAR 5.0 格式说明则规定,文件头中的文件名字段使用 UTF-8。7z 用 Unicode 保存文件名,RAR 5.0 的压缩包则规定文件名使用 UTF-8,因此不会像 ZIP 那样因有无标志而出现不同的读法。
文件内容(文本或 CSV)的乱码也是同一个原因吗?不是。APPNOTE 附录 D 写明,第 11 位既不表示文件内容的编码,也不表示密码的编码。解压后的 CSV 在 Excel 里乱码,是 CSV 本身的编码问题,需要在导入时指定编码。
ZIP 能否另外保存一份 UTF-8 的文件名?可以。APPNOTE 附录 D 介绍,Info-ZIP 的 Ed Gordon 定义了一对用于保存 UTF-8 文件名和注释的扩展字段,其中保存文件名的是 Header ID 为 0x7075 的 Info-ZIP Unicode Path Extra Field。这样无需设置第 11 位,就能同时保存原编码的文件名和 UTF-8 的文件名。不过是否支持取决于工具:2026 年 10 月检查 macOS 26.5 的 ditto 生成的 ZIP,其中并没有这个字段。
已经以乱码的文件名解压了怎么办?只要原来的 ZIP 还在,用“修复方法:重新选择文件名编码再打开”一节的方法重新解压就是最稳妥的办法。如果 ZIP 已经删除,就只能逐个手动改名了。