如何在Python中从压缩文件内的压缩文件中读取数据?

42

我有一个文件,想要读取它,该文件本身被压缩在zip归档文件中。例如,parent.zip包含child.zip,而child.zip包含child.txt。我无法读取child.zip。请问有人能够更正我的代码吗?

我推测我需要将child.zip创建为类似文件的对象,然后使用第二个zipfile实例打开它,但是由于刚学习Python,我的zipfile.ZipFile(zfile.open(name))很蠢。它会导致zipfile.BadZipfile异常:“文件不是zip文件”,尽管(child.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"
2个回答

64
当你在ZipFile实例上使用.open()调用时,确实会获得一个打开的文件句柄。然而,要读取zip文件,ZipFile类需要更多内容。它需要能够在该文件上执行寻址(seek)操作,而在您的情况下,由.open()返回的对象不可寻址。只有Python 3(3.2及以上版本)才会生成支持寻址的ZipExFile对象(假设外部zip文件的底层文件句柄是可寻址的,且没有任何东西试图写入ZipFile对象)。
解决方法是使用.read()将整个zip条目读入内存,将其存储在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"

15

为了让这在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。


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