読み取りたいファイルがあり、それ自体がZipアーカイブ内に圧縮されています。たとえば、parent.Zipには、child.txtを含むchild.Zipが含まれています。子供を読むのに問題があります。誰かが私のコードを修正できますか?
Child.Zipをファイルのようなオブジェクトとして作成し、zipfileの2番目のインスタンスで開く必要があると想定していますが、python my zipfile.ZipFile(zfile.open( name))はばかげています。それはzipfile.BadZipfileを発生させます:(独立して検証された)child.Zipで「ファイルは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"
ZipFile
インスタンスで.open()
呼び出しを使用すると、実際に開いているファイルハンドルが取得されます。ただし、read Zipファイルにするには、ZipFile
クラスにもう少し必要があります。そのファイルに対してseekが可能である必要があり、.open()
によって返されたオブジェクトはあなたの場合シークできません。 Python 3(3.2以降)のみが、シークをサポートするZipExFile
オブジェクトを生成します(外側のZipファイルの基になるファイルハンドルがシーク可能であり、何も書き込もうとしていない場合) ZipFile
オブジェクト)。
回避策は、.read()
を使用してZipエントリ全体をメモリに読み取り、BytesIO
オブジェクト(isシーク可能なメモリ内ファイル)に格納してフィードすることです。それを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"
これを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を使用しました
これが私が思いついた機能です。 ( here からコピー)
def extract_nested_zipfile(path, parent_Zip=None):
"""Returns a ZipFile specified by path, even if the path contains
intermediary ZipFiles. For example, /root/gparent.Zip/parent.Zip/child.Zip
will return a ZipFile that represents child.Zip
"""
def extract_inner_zipfile(parent_Zip, child_Zip_path):
"""Returns a ZipFile specified by child_Zip_path that exists inside
parent_Zip.
"""
memory_Zip = StringIO()
memory_Zip.write(parent_Zip.open(child_Zip_path).read())
return zipfile.ZipFile(memory_Zip)
if ('.Zip' + os.sep) in path:
(parent_Zip_path, child_Zip_path) = os.path.relpath(path).split(
'.Zip' + os.sep, 1)
parent_Zip_path += '.Zip'
if not parent_Zip:
# This is the top-level, so read from disk
parent_Zip = zipfile.ZipFile(parent_Zip_path)
else:
# We're already in a Zip, so pull it out and recurse
parent_Zip = extract_inner_zipfile(parent_Zip, parent_Zip_path)
return extract_nested_zipfile(child_Zip_path, parent_Zip)
else:
if parent_Zip:
return extract_inner_zipfile(parent_Zip, path)
else:
# If there is no nesting, it's easy!
return zipfile.ZipFile(path)
これが私がテストした方法です:
echo hello world > hi.txt
Zip wrap1.Zip hi.txt
Zip wrap2.Zip wrap1.Zip
zip wrap3.Zip wrap2.Zip
print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap1.Zip').open('hi.txt').read()
print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap2.Zip/wrap1.Zip').open('hi.txt').read()
print extract_nested_zipfile('/Users/mattfaus/dev/dev-git/wrap3.Zip/wrap2.Zip/wrap1.Zip').open('hi.txt').read()