一、问题提出
使用info-zip.org 的 unzip类 解压zip压缩包,如果压缩包中有中文文件名,那么解压这些文件出来时文件名是乱码的。
二、分析
参考这篇文章 让 Unzip 正确解压其中包含中文文件名的 Winzip 压缩包链接失效 (注:疑似转载链接),原因是 unzip 试图将 zip 文件中用 oem(ibm-dos) codepage 编码的文件名转换成自己的内部编码。可惜 unzip 只能转换极少数几种 codepage,中文的 cp936 不在其列。
三、如果您的系统还未编译安装Unzip
3.1 方法一 更改源码解决乱码
调试发现问题出现在 MultiByteToWideChar
方法里,如 MultiByteToWideChar(CP_ACP,0,fn,-1,tfn,MAX_PATH);
到这里时 fn
中的 name
属性值还是正常的,在这个方法内部执行完 tfn
就乱了。
解决方法:
打开 unzip.cpp 源文件,找到函数
ZRESULT TUnzip::Get(int index,ZIPENTRY *ze)
{
// ......
// ......
}
这个函数里有
#ifdef UNICODE
MultiByteToWideChar(CP_UTF8,0,fn,-1,tfn,MAX_PATH);
#else
strcpy(tfn,fn);
#endif
把 CP_UTF8 改为 CP_ACP(CP_ACP 指示要使用当前设置的 API 默认 Windows ANSI 代码页)
重新编译后
这样就解决了解压中文文件名称乱码的问题
3.2 方法二 编译时解决源码问题(无需更改源码)
上面的情况,我们我观察到unzip源代码这段开始的地方有判断
#ifndef Ext_ASCII_TO_Native
这样问题似乎更简单了,不用改源代码,只需在 make 时定义 Ext_ASCII_TO_Native
即可,这样 Ext_ASCII_TO_Native
实际为一个空的宏,不进行任何转换操作。
比如,使用下面的方法编译
make -DExt_ASCII_TO_Native
或者在 bash 执行下面两行
export LOCAL_UNZIP=-DExt_ASCII_TO_Native
make
unzip 解压缩含中文文件名 zip 包是出现乱码的问题解决!
四、如果您的系统已经安装了 unzip
4.1 方法一 unzip 行命令解压,指定字符集
通过 unzip 行命令解压,指定字符集
unzip -O CP936 xxx.zip # 用GBK, GB18030 也可以
4.2 方法二 在环境变量中,指定 unzip 参数
在环境变量中,指定 unzip 参数,总是以指定的字符集显示和解压文件
/etc/environment 中加入 2 行
UNZIP="-O CP936"
ZIPINFO="-O CP936"
4.3 方法三 利用 python 来处理
复制以下内容(Python)保存为 myuzip.py 文件脚本,并修改运行权限为可运行(chmod +x uzip
)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# uzip.py
import os
import sys
import zipfile
print "Processing File " + sys.argv[1]
file=zipfile.ZipFile(sys.argv[1],"r");
for name in file.namelist():
utf8name=name.decode('gbk')
print "Extracting " + utf8name
pathname = os.path.dirname(utf8name)
if not os.path.exists(pathname) and pathname!= "":
os.makedirs(pathname)
data = file.read(name)
if not os.path.exists(utf8name):
fo = open(utf8name, "w")
fo.write(data)
fo.close
file.close()
这样以后我们解压缩时只需要运行此文件即可
./myuzip.py xxxx.zip