Python - 从大型(6GB +)zip文件中提取文件

时间:2014-01-02 20:09:10

标签: python compression zlib zipfile

我有一个Python脚本,我需要提取ZIP文件的内容。但是,zip文件的大小超过6GB。

有很多关于zlibzipfile模块的信息,但是,我无法找到适用于我的案例的单一方法。 我有代码:

with zipfile.ZipFile(fname, "r") as z:
        try:
            log.info("Extracting %s " %fname)
            head, tail = os.path.split(fname)
            z.extractall(folder + "/" + tail)
        except zipfile.BadZipfile:
            log.error("Bad Zip file")
        except zipfile.LargeZipFile:
            log.error("Zip file requires ZIP64 functionality but that has not been enabled (i.e., too large)")
        except zipfile.error:
            log.error("Error decompressing ZIP file")

我知道我需要将allowZip64设置为true,但我不确定如何执行此操作。然而,即使是这样,也不会抛出LargeZipFile异常,而是BadZipFile异常。我不明白为什么。

另外,这是处理提取6GB zip存档的最佳方法吗?

更新: 修改BadZipfile例外:

except zipfile.BadZipfile as inst:
        log.error("Bad Zip file")
        print type(inst)     # the exception instance
        print inst.args      # arguments stored in .args
        print inst

所示:

<class 'zipfile.BadZipfile'>
('Bad magic number for file header',)

更新#2:

完整的追溯显示

BadZipfile                                Traceback (most recent call last)
<ipython-input-1-8d34a9f58f6a> in <module>()
      6     for member in z.infolist():
      7         print member.filename[-70:],
----> 8         f = z.open(member, 'r')
      9         size = 0
     10         while True:

/Users/brspurri/anaconda/python.app/Contents/lib/python2.7/zipfile.pyc in open(self, name, mode, pwd)
    965             fheader = struct.unpack(structFileHeader, fheader)
    966             if fheader[_FH_SIGNATURE] != stringFileHeader:
--> 967                 raise BadZipfile("Bad magic number for file header")
    968 
    969             fname = zef_file.read(fheader[_FH_FILENAME_LENGTH])

BadZipfile: Bad magic number for file header

运行代码:

import sys
import zipfile

with open(zip_filename, 'rb') as zf:
    z = zipfile.ZipFile(zf, allowZip64=True)
    z.testzip()

doesn't output anything.

1 个答案:

答案 0 :(得分:7)

问题是您的zip文件已损坏。我可以在下面添加有关腐败的更多细节,但首先是实用的东西:

您可以使用this code snippet告诉您存档中的哪个成员已损坏。但是,print z.testzip()已经告诉你同样的事情了。命令行上的zip -Tunzip也应该为您提供具有适当详细程度的信息。


那么,你怎么办呢?

嗯,显然,如果你能得到一份未经破坏的文件副本,那就去做吧。

如果没有,如果你想跳过坏文件并提取其他所有内容,这很容易 - 大多数代码与上面链接的代码段相同:

with open(sys.argv[1], 'rb') as zf:
    z = zipfile.ZipFile(zf, allowZip64=True)
    for member in z.infolist():
        try:
            z.extract(member)
        except zipfile.error as e:
            # log the error, the member.filename, whatever

Bad magic number for file header异常消息表示zipfile能够成功打开zip文件,解析其目录,查找成员的信息,在归档中寻找该成员,并阅读标题该成员 - 所有这些意味着您可能在这里没有与zip64相关的问题。但是,当它读取该标题时,它没有PK\003\004的预期“魔术”签名。这意味着存档已损坏。

腐败恰好恰好是4294967296这一事实非常强烈地暗示你在链的某处有一个64位问题,因为那正是2 ** 32。


命令行zip / unzip工具有一些解决方法可以解决导致此类问题的腐败的常见原因。看起来这些变通办法可能适用于此存档,因为您收到警告,但所有文件都显然已恢复。 Python的zipfile库没有这些解决方法,我怀疑你想自己编写zip - 自己处理代码......

然而,这确实为另外两种可能性敞开了大门:

首先,zip可以使用-F -FF标记为您修复 zipfile。 (阅读联机帮助页,或zip -h,或者在SuperUser等网站上询问是否需要帮助。)

如果所有其他方法都失败了,您可以从Python运行unzip工具,而不是使用zipfile,如下所示:

subprocess.check_output(['unzip', fname])

当然,这比zipfile模块给你的灵活性和功率要低得多 - 但你无论如何都没有使用任何灵活性;你只是打电话给extractall

相关问题