原因分析
zipfile.py中ZipFile在初始化时执行了_RealGetContents方法,目的是读取目录结构,其中关于文件名编码的处理是这样的:
# 第42行
if flags & 0x800:
# UTF-8 file names extension
filename = filename.decode('utf-8')
else:
# Historical ZIP filename encoding
filename = filename.decode('cp437')
要么是utf-8
要么是cp437
,然而咱们在windows平台上压缩包文件名编码大多是gbk,这里用cp437
解码了,所以会乱码
解决办法
只需要将filename重新编码cp437解码成gbk就好了,网络上大多数做法是对解压后的文件和目录操作,不太优雅。优雅一点点的方式是直接修改ZipFile对象中的filename
首先找到filename存在于哪里,同样在_RealGetContents这个函数中找到如下代码
# 第49行
x = ZipInfo(filename)
... # 省略若干行
# self是ZipFile对象
# 第67行
self.filelist.append(x)
self.NameToInfo[x.filename] = x
from zipfile import ZipFile
def support_gbk(zip_file: ZipFile):
name_to_info = zip_file.NameToInfo
# copy map first
for name, info in name_to_info.copy().items():
real_name = name.encode('cp437').decode('gbk')
if real_name != name:
info.filename = real_name
del name_to_info[name]
name_to_info[real_name] = info
return zip_file
with support_gbk(ZipFile(r'./里面有中文.zip')) as zfp:
zfp.extractall(r'./中文不乱码')