2016-06-09 183 views
4

问题是,对于一些档案或文件上传到python应用程序,ZipFilenamelist()返回严重解码的字符串。ZipFile的namelist()返回一个编码无效的字符串

from zip import ZipFile 
for name in ZipFile('zipfile.zip').namelist(): 
    print('Listing zip files: %s' % name) 

如何修复该代码,所以我总是解码unicode中的文件名(所以支持Chineeze,俄语和其他语言)?

我见过Python 2的一些示例,但由于字符串的本质在python3中发生了变化,我不知道如何重新编码它,或者对它应用chardet。

+0

HT tp://stackoverflow.com/questions/1807063/extract-files-with-invalid-characters-in-filename-with-python可能会给你一些答案,特别是第二个答案。 – Kush131

回答

4

如何解决该代码,所以我总是在unicode解码文件名(所以Chineeze,俄罗斯和其他语言支持)?

自动?你不能。基本ZIP文件中的文件名是字节串,没有附加的编码信息,因此除非您知道创建ZIP的计算机上的编码,否则无法可靠地获取可读的文件名。

对现代ZIP文件的标志有一个扩展名,告诉你文件名是UTF-8。不幸的是,你从Windows用户那里收到的文件通常没有它,所以你会用像chardet这样固有的不可靠方法进行猜测。

我已经看到了Python 2的一些示例,但由于字符串的本质在python3中发生了变化,我不知道如何对其进行重新编码或对其应用chardet。

Python 2只会给你原始字节。在Python 3的新特性是:

  • 如果UTF-8标志设置,它使用UTF-8解码文件名,你会得到正确的字符串值回

  • 否则,解码使用DOS代码页面437的文件名,这很可能不是预期的。但是,您可以将字符串重新编码回原始字节,然后尝试使用您实际需要的代码页再次解码,例如name.encode('cp437').decode('cp1252')

不幸的是(再次,因为unfortunatelies永远不会结束,其中ZIP而言),ZipFile默默的做这个解码不告诉你它的所作所为。所以,如果你想切换,只有做转码的步骤,当文件名是犯罪嫌疑人,你必须复制的逻辑嗅探UTF-8标志是否被设置:

ZIP_FILENAME_UTF8_FLAG = 0x800 

for info in ZipFile('zipfile.zip').filelist(): 
    filename = info.filename 
    if info.flag_bits & ZIP_FILENAME_UTF8_FLAG == 0: 
     filename_bytes = filename.encode('437') 
     guessed_encoding = chardet.detect(filename_bytes)['encoding'] or 'cp1252' 
     filename = filename_bytes.decode(guessed_encoding, 'replace') 
    ... 
0

这里的解码文件名中zipfile.py代码根据the zip spec that supports only cp437 and utf-8 character encodings

 if flags & 0x800: 
      # UTF-8 file names extension 
      filename = filename.decode('utf-8') 
     else: 
      # Historical ZIP filename encoding 
      filename = filename.decode('cp437') 

正如你所看到的,如果0x800标志不是IE设置,如果UTF-8是不是在你的输入使用zipfile.zip然后cp437被使用,因此结果为“Chineeze,俄罗斯和其他语言“可能是不正确的。

实际上,可以使用ANSI或OEM Windows代码页代替cp437。

如果你知道实际的字符编码如cp866 (OEM (console) codepage) may be used on Russian Windows那么你可以重新编码的文件名来获得原始文件名:

filename = corrupted_filename.encode('cp437').decode('cp866') 

最好的办法是使用UTF-8,这样就可以支持创建ZIP档案在同一归档多国语言:

c:\> 7z.exe a -tzip -mcu archive.zip <files>.. 

​​
相关问题