Ich möchte eine Datei lesen, die selbst in einem Zip-Archiv komprimiert ist. Zum Beispiel enthält parent.Zip child.Zip, das child.txt enthält. Ich habe Probleme beim Lesen des Kindes.Zip. Kann jemand meinen Code korrigieren?
Ich gehe davon aus, dass ich child.Zip als dateiähnliches Objekt erstellen und es dann mit einer zweiten Instanz von zipfile öffnen muss, aber wenn ich neu in Python bin, ist mein zipfile.ZipFile (zfile.open (name)) albern. Es löst eine zip-Datei aus.BadZip-Datei: "Datei ist keine zip-Datei" auf child.Zip (unabhängig validiert)
import zipfile
with zipfile.ZipFile("parent.Zip", "r") as zfile:
for name in zfile.namelist():
if re.search(r'\.Zip$', name) != 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"
Wenn Sie den Aufruf .open()
in einer ZipFile
-Instanz verwenden, wird tatsächlich ein offener Datei-Handle angezeigt. Um read a Zip-Datei zu benötigen, benötigt die ZipFile
-Klasse jedoch etwas mehr. Es muss in der Lage sein, seek für diese Datei und das von .open()
zurückgegebene Objekt ist nicht suchbar.
Um das Problem zu umgehen, lesen Sie den gesamten Zip-Eintrag mit .read()
in den Speicher, speichern ihn in einem BytesIO
-Objekt (einer In-Memory-Datei, die ist durchsuchbar), und geben Sie diese an ZipFile
:
from io import BytesIO
# ...
zfiledata = BytesIO(zfile.read(name))
with zipfile.ZipFile(zfiledata) as zfile2:
oder im Zusammenhang mit Ihrem Beispiel:
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) != None:
# We have a Zip within a Zip
zfiledata = BytesIO(zfile.read(name))
with zipfile.ZipFile(zfiledata) as zf
for name2 in zfile2.namelist():
# Now we can extract
logging.info( "Found internal internal file: " + name2)
print "Processing code goes here"
Damit dies mit python33 funktioniert (unter Windows, aber das ist vielleicht nicht relevant), musste ich Folgendes tun:
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 existiert nicht, also habe ich io.BytesIO verwendet
Hier ist eine Funktion, die ich mir ausgedacht habe. (Kopiert von hier .)
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)
So habe ich es getestet:
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()