zipfile无法处理某些类型的zip数据?

10

我在尝试解压缩一个zip文件时遇到了这个问题。

-- zipfile.is_zipfile(my_file) 总是返回False,即使UNIX命令 unzip 可以正常处理它。当尝试执行 zipfile.ZipFile(path/file_handle_to_path) 时,我也会收到相同的错误信息。

-- 运行 file 命令返回 Zip archive data, at least v2.0 to extract,并且使用 less 命令查看该文件时显示:

PKZIP for iSeries by PKWARE
 Length      Method Size      Cmpr Date       Time  CRC-32    Name
 2113482674  Defl:S 204502989  90% 2010-11-01 08:39 2cee662e  myfile.txt
 2113482674         204502989  90%                            1 file
有什么办法可以解决这个问题吗?如果我切换到运行subprocess.call("unzip")的方式,那我就必须放弃一些单元测试,所以如果我能让Python的zipfile正常工作就好了。

2
导入 os 并告诉我们 os.path.exists(my_file) 返回什么。 - eumiro
@hyperboreean - 我觉得你可能会遇到文件名的问题,因为zipfile.is_zipfile对于不存在的文件也会返回False - eumiro
看起来你可能有一个类似于 https://dev59.com/AnA75IYBdhLWcg3w0st- 的问题。不幸的是,那个发帖人没有得到解决方案。 :( - ire_and_curses
文件大小是多少,超过1GB了吗? - Paulo Scardine
1
@hyperboreean:你能把一个zip文件上传到某个地方来展示这个问题吗?有一些测试数据的话,可能更容易找出实际的问题所在。 - aknuds1
显示剩余4条评论
3个回答

7

我曾遇到相同的问题,但最终解决了。我不确定这些文件是如何生成的,就像上面的例子一样。它们在结尾处都有被Windows和7z忽略的尾随数据,并导致Python的zipfile失败。

以下是解决该问题的代码:

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("Truncating 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  

2
我不知道这是否是Python版本问题,但我收到了TypeError:参数应该是整数或类似字节的对象,而不是“str”。通过将“data.find”括号后面的所有内容替换为b'\x50\x4b\x05\x06'来解决此问题。 - morph3us
同样的 @morph3us,你最终找到解决方案了吗? - Tomer Cahal

1
你说使用less在文件上显示如此如此。你是指这个吗?
less my_file

如果是这样,我猜测这些是zip程序放在文件中的注释。查看我在网上找到的iSeries PKZIP用户指南,这似乎是默认行为。

zipfile文档说:“此模块目前不处理附加了注释的ZIP文件。”也许这就是问题所在?(当然,如果less显示它们,这似乎意味着它们是“预置”的。)

看起来您(或在iSeries机器上创建zip文件的人)可以使用ARCHTEXT(* NONE)关闭此功能,或使用ARCHTEXT(* CLEAR)从现有zip文件中删除它。


0
# Utilize mmap module to avoid a potential DoS exploit (e.g. by reading the
# whole zip file into memory). A bad zip file example can be found here:
# https://bugs.python.org/issue24621

import mmap
from io import UnsupportedOperation
from zipfile import BadZipfile

# The end of central directory signature
CENTRAL_DIRECTORY_SIGNATURE = b'\x50\x4b\x05\x06'


def repair_central_directory(zipFile):
    if hasattr(zipFile, 'read'):
        # This is a file-like object
        f = zipFile
        try:
            fileno = f.fileno()
        except UnsupportedOperation:
            # This is an io.BytesIO instance which lacks a backing file.
            fileno = None
    else:
        # Otherwise, open the file with binary mode
        f = open(zipFile, 'rb+')
        fileno = f.fileno()
    if fileno is None:
        # Without a fileno, we can only read and search the whole string
        # for the end of central directory signature.
        f.seek(0)
        pos = f.read().find(CENTRAL_DIRECTORY_SIGNATURE)
    else:
        # Instead of reading the entire file into memory, memory-mapped the
        # file, then search it for the end of central directory signature.
        # Reference: https://dev59.com/Y3A75IYBdhLWcg3wlqET#21844624
        mm = mmap.mmap(fileno, 0)
        pos = mm.find(CENTRAL_DIRECTORY_SIGNATURE)
        mm.close()
    if pos > -1:
        # size of 'ZIP end of central directory record'
        f.truncate(pos + 22)
        f.seek(0)
        return f
    else:
        # Raise an error to make it fail fast
        raise BadZipfile('File is not a zip file')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接