一直以来,我发现在 Mac OS X 中,不论用 Stuffit Expander 还是命令行下的 unzip,解压缩 Windows 下生成的某些 ZIP 文件时,解出来的中文文件名会变成乱码。不过,这种情况出现的次数很少,没有引起我的重视。今天终于觉得不能忍了,以几个简单关键词在 Google 上搜索,好像没有发现专门说这件事情的。于是决心花点时间研究它。
我在 Windows 下的 ZIP 文件大多数是用 7-Zip 这个自由软件生成的。虽然它的强项在于自己的 7z 格式,不过出于兼容性的考虑,我只是用它压缩 ZIP 格式文件,并解压缩所有常见的压缩文件格式。ZIP 文件标准自创立之初就没有、现在也没有记录文件名编码的信息,所以有很大一批 ZIP 文件都是以压缩包的创建者本地 locale 编码的,比如我遇到问题的几个 ZIP 文件内部的文件名就是用简体中文 GBK 编码的。而我 Mac OS X 的 locale 是 en_US.UTF-8,解开后自然不能正确识别 GBK 编码的文件名了。
阅读了 ZIP 文件格式这个 Wikipedia 条目,我发现最新的 ZIP 标准中建议使用 UTF-8 作为文件名的编码。这一点并不出乎意料,显然对于跨平台的需求,UTF-8 的编码是最理想的选择。下面的问题就是如何让 7-Zip 生成以 UTF-8 编码被压缩文件名的 ZIP 文件了。
在 Windows 下进行试验,我发现一个有意思的现象:当 Windows 系统的 locale 为简体中文(中国)时(“控制面板-区域和语言选项-高级-为非Unicode程序的语言选择 - Chinese (PRC)”),7-Zip 压缩出来的 ZIP 文件以 GBK 编码被压缩文件名;而当 Windows 系统的 locale 为英语(美国)时,压缩出来的 ZIP 文件编码竟然是 UTF-8!此外,在中文 locale 下,不论是以 GBK 还是 UTF-8 编码文件名的 ZIP 文件都能正常解开;而在英文 locale 下,只能解开 UTF-8 编码的文件,GBK 编码的文件解出来就是乱码。这表明, 7-Zip 是有处理 UTF-8 编码文件名的功能的。但是,为什么仅仅对英语(美国)代码页(也就是最基本的 ASCII )才会使用 UTF-8 呢?
继续查找,发现 UTF-8 的版本历史里面,自从 4.58 版本以来引入了 ZIP 内部文件名编码的概念。默认模式是,对于生成 ZIP 文件的文件名,如果当前 locale 代码页中有相应字符,就用当前代码页;如果没有,就使用 UTF-8。同时,7-Zip 也提供了两个模式,强制以 UTF-8 编码文件名,或强制以当前 locale 编码文件名(即不作转换)。
了解了这一点,解决方法就变得简单了:压缩 ZIP 文件时,使用 -mcu 选项强制使用 UTF-8 作为压缩文件名的编码。图形界面中的操作如下:
需要注意的是,7-Zip 的 Explorer shell 右键菜单中“Add to .zip” 这个项目只能以默认参数生成 ZIP 文件。如果希望生成在其他平台不出现乱码的 UTF-8 编码 ZIP 文件,就只能使用 “Add to archive…” 菜单项了。