解压文件时出现“BadZipFile: 文件不是zip文件”
我有两个压缩文件,它们在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