40

我有一个我想阅读的文件,它本身压缩在一个 zip 存档中。例如,parent.zip 包含 child.zip,其中包含 child.txt。我在阅读 child.zip 时遇到问题。任何人都可以更正我的代码吗?

我假设我需要将 child.zip 创建为类似文件的对象,然后使用第二个 zipfile 实例打开它,但是对于 python 来说,我的 zipfile.ZipFile(zfile.open(name)) 很愚蠢。它会在(独立验证的)child.zip 上引发一个 zipfile.BadZipfile:“文件不是 zip 文件”

import zipfile
with zipfile.ZipFile("parent.zip", "r") as zfile:
    for name in zfile.namelist():
        if re.search(r'\.zip$', name) is not None:
            # We have a zip within a zip
            with **zipfile.ZipFile(zfile.open(name))** as zfile2:
                    for name2 in zfile2.namelist():
                        # Now we can extract
                        logging.info( "Found internal internal file: " + name2)
                        print "Processing code goes here"
4

2 回答 2

58

当您.open()在实例上使用调用时,ZipFile您确实会获得一个打开的文件句柄。但是,要读取zip 文件,ZipFile该类还需要更多内容。它需要能够在该文件上查找,并且在您的情况下,返回的对象.open()不可查找的。只有 Python 3(3.2 及更高版本)生成ZipExFile支持查找的对象(前提是外部 zip 文件的底层文件句柄是可查找的,并且没有尝试写入该ZipFile对象)。

解决方法是使用 将整个 zip 条目读取到内存中.read(),将其存储在一个对象(可查找BytesIO内存文件)中并将其提供给:ZipFile

from io import BytesIO

# ...
        zfiledata = BytesIO(zfile.read(name))
        with zipfile.ZipFile(zfiledata) as zfile2:

或者,在您的示例中:

import zipfile
from io import BytesIO

with zipfile.ZipFile("parent.zip", "r") as zfile:
    for name in zfile.namelist():
        if re.search(r'\.zip$', name) is not None:
            # We have a zip within a zip
            zfiledata = BytesIO(zfile.read(name))
            with zipfile.ZipFile(zfiledata) as zfile2:
                for name2 in zfile2.namelist():
                    # Now we can extract
                    logging.info( "Found internal internal file: " + name2)
                    print "Processing code goes here"
于 2012-08-19T09:25:03.693 回答
13

为了让它与 python33 一起工作(在 windows 下,但这可能无关紧要),我必须这样做:

 import zipfile, re, io
    with zipfile.ZipFile(file, 'r') as zfile:
        for name in zfile.namelist():
            if re.search(r'\.zip$', name) != None:
                zfiledata = io.BytesIO(zfile.read(name))
                with zipfile.ZipFile(zfiledata) as zfile2:
                    for name2 in zfile2.namelist():
                        print(name2)

cStringIO 不存在,所以我使用了 io.BytesIO

于 2013-11-20T14:57:29.643 回答