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

10 投票
3 回答
17670 浏览
提问于 2025-04-16 11:23

我在尝试解压一个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

有没有什么办法可以解决这个问题?如果我能让 Python 的 zipfile 正常工作就好了,因为我已经有一些单元测试,如果我改用 subprocess.call("unzip") 的话就得放弃这些测试了。

3 个回答

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://stackoverflow.com/a/21844624/2293304
        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')

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

1

你说用 less 查看文件时显示了某些内容。你是指这个吗?

less my_file

如果是这样的话,我猜这些是压缩程序在文件中添加的注释。从我在网上找到的iSeries PKZIP用户手册来看,这似乎是默认的行为。

关于 zipfile 的文档提到:“这个模块目前不处理带有附加注释的ZIP文件。”也许这就是问题所在?(当然,如果 less 能显示这些内容,那就说明它们是前置的,仅供参考。)

看起来你(或者在iSeries机器上创建这个zip文件的人)可以通过 ARCHTEXT(*NONE) 来关闭这个功能,或者使用 ARCHTEXT(*CLEAR) 从现有的zip文件中移除它。

8

我在我的文件中也遇到了同样的问题,并且成功解决了。对于这些文件是怎么生成的,我也不太清楚,就像上面的例子一样。它们的末尾都有一些多余的数据,这些数据在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  

撰写回答