问题
python 使用zipfile库来解压apk压缩文件的时候,出现了报错zipfile.BadZipfile: File name in directory "AndroidManifest.xml" and header "META-INF/MANIFEST.MF" differ.
剖析问题
根据异常日志,
File “c:\Python27\lib\zipfile.py”, line 1028, in extract
return self._extract_member(member, path, pwd)
File “c:\Python27\lib\zipfile.py”, line 1082, in _extract_member
with self.open(member, pwd=pwd) as source,
File “c:\Python27\lib\zipfile.py”, line 980, in open
zinfo.orig_filename, fname)
zipfile.BadZipfile: File name in directory “AndroidManifest.xml” and header “META-INF/MANIFEST.MF” differ.
抛出异常的地方是:c:\Python27\lib\zipfile.py", line 980
,我们去代码处看看,到底干了什么?
从下面代码可以看出,这是个打开压缩文件的函数,找准关键点fname != zinfo.orig_filename
这两个变量是关键,fname = zef_file.read(fheader[_FH_FILENAME_LENGTH]) 这个语句大致可以从命名看出是读取文件头一定偏移处的内容,大概。zinfo.orig_filename
这个是zipinfo对象的文件名,也就是我想提取出来的文件名称,是zipinfo对象的一个属性,也就是可能是文件头一定偏移处的内容和要提取的文件名对比,出现的不同
def open(self, name, mode="r", pwd=None):
"""Return file-like object for 'name'."""
if mode not in ("r", "U", "rU"):
raise RuntimeError, 'open() requires mode "r", "U", or "rU"'
if not self.fp:
raise RuntimeError, \
"Attempt to read ZIP archive that was already closed"
# Only open a new file for instances where we were not
# given a file object in the constructor
if self._filePassed:
zef_file = self.fp
should_close = False
else:
zef_file = open(self.filename, 'rb')
should_close = True
try:
# Make sure we have an info object
if isinstance(name, ZipInfo):
# 'name' is already an info object
zinfo = name
else:
# Get info object for name
zinfo = self.getinfo(name)
zef_file.seek(zinfo.header_offset, 0)
# Skip the file header:
fheader = zef_file.read(sizeFileHeader)
if len(fheader) != sizeFileHeader:
raise BadZipfile("Truncated file header")
fheader = struct.unpack(structFileHeader, fheader)
if fheader[_FH_SIGNATURE] != stringFileHeader:
raise BadZipfile("Bad magic number for file header")
fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])
if fheader[_FH_EXTRA_FIELD_LENGTH]:
zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH])
if fname != zinfo.orig_filename:
raise BadZipfile, \
'File name in directory "%s" and header "%s" differ.' % (
zinfo.orig_filename, fname)
为了确认上面的分析的正确性,我们看看这个zip包的文件结构
下面是一个可以使用zipfile提取文件的压缩包的文件结构,我们对比一下,可以看出确实是文件头这块除了问题。然后尝试提取这个有出现问题zip包的其他文件,是可以提取的
解决方法
上面这个问题的解决方法我自己没有找到办法,如果有大佬知道,欢迎评论。
暂时使用别的方法来替代这个zipfile压缩库,我选择的是使用java 写一个jar解压工具,使用流的方式来解压缩