Python zipfile模块无法提取带有中文字符的文件名

hyp*_*ser 5 unicode zipfile python-2.7

我正在尝试使用python脚本从中国的服务提供商下载文件(我自己不是从中国)。提供程序给我一个.zip文件,其中包含一个文件名似乎带有汉字的文件。这似乎导致zipfile模块出现故障。

码:

import zipfile

f = "/path/to/zip_file.zip"

if zipfile.is_zipfile(f):
    fz = zipfile.ZipFile(f, 'r')
Run Code Online (Sandbox Code Playgroud)

zipfile本身不包含任何非ASCII字符,但其中的文件包含。当我运行上述脚本时,出现以下异常:

Traceback (most recent call last):   File "./temp.py", line 9, in <module>
    fz = zipfile.ZipFile(f, 'r')   File "/usr/lib/python2.7/zipfile.py", line 770, in __init__
    self._RealGetContents()   File "/usr/lib/python2.7/zipfile.py", line 859, in _RealGetContents
    x.filename = x._decodeFilename()   File "/usr/lib/python2.7/zipfile.py", line 379, in _decodeFilename
    return self.filename.decode('utf-8')   File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError: 'utf8' codec can't decode byte 0xbd in position 30: invalid start byte
Run Code Online (Sandbox Code Playgroud)

我尝试浏览许多类似问题的答案:

如果我输入错了,请纠正我,但它似乎是zipfile模块未解决问题

我该如何解决?我应该使用其他替代模块来处理zip文件吗?或其他解决方案?

TIA。

编辑:我可以使用linux命令行实用程序“ unzip”完美地访问/解压缩同一文件。

sec*_*ilm 7

最近我遇到了同样的问题。这是我的解决方案。我希望它对你有用。

import shutil
import zipfile
f = zipfile.ZipFile('/path/to/zip_file.zip', 'r')
for fileinfo in f.infolist():
    filename = fileinfo.filename.encode('cp437').decode('gbk')
    outputfile = open(filename, "wb")
    shutil.copyfileobj(f.open(fileinfo.filename), outputfile)
    outputfile.close()
f.close()
Run Code Online (Sandbox Code Playgroud)

更新:您可以使用以下更简单的解决方案pathlib

from pathlib import Path
import zipfile

with zipfile.ZipFile('/path/to/zip_file.zip', 'r') as f:
    for fn in f.namelist():
        extracted_path = Path(f.extract(fn))
        extracted_path.rename(fn.encode('cp437').decode('gbk'))
Run Code Online (Sandbox Code Playgroud)


soc*_*tes 5

Python 2.x(2.7)和Python 3.x处理模块zipfile中非utf-8文件名的方式有些不同。

首先,它们都检查文件的ZipInfo.flag_bits,如果ZipInfo.flag_bits&0x800,则将使用utf-8解码文件名。

如果以上检查为False,则在Python 2.x中,将返回名称的字节字符串;否则,返回false。在Python 3.x中,模块将使用cp437编码对文件进行解码,并返回解码后的结果。当然,在两个Python版本中,模块都不知道文件名的真实编码。

因此,假设您从ZipInfo对象或zipfile.namelist方法获得了文件名,并且您已经知道该文件名是使用XXX编码编码的。这些是您获取正确的unicode文件名的方法:

# in python 2.x
filename = filename.decode('XXX')


# in python 3.x
filename = filename.encode('cp437').decode('XXX')
Run Code Online (Sandbox Code Playgroud)

  • 要了解哪个代码“XXX”对应于您的语言,请检查[此处适用于 python 2.4](https://docs.python.org/2.4/lib/standard-encodings.html) 或[此处适用于 python 3.x]( https://docs.python.org/3/library/codecs.html#standard-encodings)。 (3认同)

bob*_*nce 1

ZIP 文件无效。它有一个标志,表明其中的文件名被编码为 UTF-8,但实际上并非如此;它们包含作为 UTF-8 无效的字节序列。也许他们是GBK?也许还有别的事?也许是一些邪恶的不一致的混合物?不幸的是,野外的 ZIP 工具在一致地处理非 ASCII 文件名方面非常非常差。

一个快速的解决方法可能是替换解码文件名的库函数。这是一个猴子补丁,因为没有一种简单的方法可以将您自己的 ZipInfo 类注入 ZipFile,但是:

zipfile.ZipInfo._decodeFilename = lambda self: self.filename
Run Code Online (Sandbox Code Playgroud)

将禁用解码文件名的尝试,并始终返回带有字节字符串filename属性的 ZipInfo,您可以继续以任何适当的方式手动解码/处理。