解压文件时出现“BadZipFile: 文件不是zip文件”

68 投票
16 回答
271023 浏览
提问于 2025-04-16 00:14

我有两个压缩文件,它们在Windows资源管理器和7-zip中都能正常打开。

但是当我用Python的zipfile模块打开它们时,发现其中一个能打开,但另一个却报错,提示“BadZipfile: File is not a zip file”。

我确认那个出问题的文件确实是一个有效的压缩文件,因为我用7-Zip打开它并查看属性,显示的是7Zip.ZIP。当我用文本编辑器打开这个文件时,前两个字符是“PK”,这说明它确实是一个压缩文件。

我使用的是Python 2.5,真的不知道该怎么解决这个问题。我在Windows和Ubuntu上都试过,问题在两个平台上都存在。

更新:这是在Windows上使用Python 2.5.4时的错误追踪信息:

Traceback (most recent call last):
File "<module1>", line 5, in <module>
    zipfile.ZipFile("c:/temp/test.zip")
File "C:\Python25\lib\zipfile.py", line 346, in init
    self._GetContents()
File "C:\Python25\lib\zipfile.py", line 366, in _GetContents
    self._RealGetContents()
File "C:\Python25\lib\zipfile.py", line 378, in _RealGetContents
    raise BadZipfile, "File is not a zip file"
BadZipfile: File is not a zip file

基本上,当调用_EndRecData函数以获取“中央目录结束记录”的数据时,评论长度检查失败了 [ endrec[7] == len(comment) ]。

_EndRecData函数中的局部变量值如下:

 END_BLOCK: 4096,
 comment: '\x00',
 data: '\xd6\xf6\x03\x00\x88,N8?<e\xf0q\xa8\x1cwK\x87\x0c(\x82a\xee\xc61N\'1qN\x0b\x16K-\x9d\xd57w\x0f\xa31n\xf3dN\x9e\xb1s\xffu\xd1\.....', (truncated)
 endrec: ['PK\x05\x06', 0, 0, 4, 4, 268, 199515, 0],
 filesize: 199806L,
 fpin: <open file 'c:/temp/test.zip', mode 'rb' at 0x045D4F98>,
 start: 4073

16 个回答

13

astronautlevel 提出的解决方案在大多数情况下都能用,但在 Zip 文件中,压缩的数据和 CRC(循环冗余校验)也可能包含相同的四个字节。你应该使用 rfind(而不是 find),然后定位到 pos+20 的位置,最后在文件末尾添加 \x00\x00(这样可以告诉 Zip 应用程序“注释”部分的长度是 0 字节)。


    # HACK: See http://bugs.python.org/issue10694
    # The zip file generated is correct, but because of extra data after the 'central directory' section,
    # Some version of python (and some zip applications) can't read the file. By removing the extra data,
    # we ensure that all applications can read the zip without issue.
    # The ZIP format: http://www.pkware.com/documents/APPNOTE/APPNOTE-6.3.0.TXT
    # Finding the end of the central directory:
    #   http://stackoverflow.com/questions/8593904/how-to-find-the-position-of-central-directory-in-a-zip-file
    #   http://stackoverflow.com/questions/20276105/why-cant-python-execute-a-zip-archive-passed-via-stdin
    #       This second link is only losely related, but echos the first, "processing a ZIP archive often requires backwards seeking"
    content = zipFileContainer.read()
    pos = content.rfind('\x50\x4b\x05\x06') # reverse find: this string of bytes is the end of the zip's central directory.
    if pos>0:
        zipFileContainer.seek(pos+20) # +20: see secion V.I in 'ZIP format' link above.
        zipFileContainer.truncate()
        zipFileContainer.write('\x00\x00') # Zip file comment length: 0 byte length; tell zip applications to stop reading.
        zipFileContainer.seek(0)

    return zipFileContainer
15

我也遇到过同样的问题。我的问题是文件是gzip格式,而不是zip格式。我换用了gzip.GzipFile这个类,结果就顺利解决了。

22

如果你把文件命名为“file”,可能会让Python搞混,所以试着换个名字。如果这样做了还是不行,那就试试下面的代码:

def fixBadZipfile(zipFile):  
 f = open(zipFile, 'r+b')  
 data = f.read()  
 pos = data.find('\x50\x4b\x05\x06') # End of central directory signature  
 if (pos > 0):  
     self._log("Trancating file at location " + str(pos + 22)+ ".")  
     f.seek(pos + 22)   # size of 'ZIP end of central directory record' 
     f.truncate()  
     f.close()  
 else:  
     # raise error, file is truncated  

撰写回答