password not name make how create compress python ziparchive

not - zipfile python 3



archivo sobrescrito en ziparchive (2)

Tengo archive.zip con dos archivos: hello.txt y world.txt

Quiero sobrescribir el archivo hello.txt con uno nuevo con ese código:

import zipfile z = zipfile.ZipFile(''archive.zip'',''a'') z.write(''hello.txt'') z.close()

pero no sobrescribirá el archivo, de alguna manera crea otra instancia de hello.txt - mira la captura de pantalla de winzip:

Ya que no hay un smth como zipfile.remove() , ¿cuál es la mejor manera de manejar este problema?


No hay manera de hacer eso con el módulo zipfile de Python. Debe crear un nuevo archivo zip y volver a comprimir todo desde el primer archivo, más el nuevo archivo modificado.

A continuación hay un código para hacer precisamente eso. Pero tenga en cuenta que no es eficiente, ya que descomprime y luego vuelve a comprimir todos los datos.

import tempfile import zipfile import shutil import os def remove_from_zip(zipfname, *filenames): tempdir = tempfile.mkdtemp() try: tempname = os.path.join(tempdir, ''new.zip'') with zipfile.ZipFile(zipfname, ''r'') as zipread: with zipfile.ZipFile(tempname, ''w'') as zipwrite: for item in zipread.infolist(): if item.filename not in filenames: data = zipread.read(item.filename) zipwrite.writestr(item, data) shutil.move(tempname, zipfname) finally: shutil.rmtree(tempdir)

Uso:

remove_from_zip(''archive.zip'', ''hello.txt'') with zipfile.ZipFile(''archive.zip'', ''a'') as z: z.write(''hello.txt'')


Sobre la base de la respuesta de Nosklo. UpdateableZipFile Una clase que hereda de ZipFile, mantiene la misma interfaz pero agrega la capacidad de sobrescribir archivos (a través de writestr o write) y eliminar archivos.

import os import shutil import tempfile from zipfile import ZipFile, ZIP_STORED, ZipInfo class UpdateableZipFile(ZipFile): """ Add delete (via remove_file) and update (via writestr and write methods) To enable update features use UpdateableZipFile with the ''with statement'', Upon __exit__ (if updates were applied) a new zip file will override the exiting one with the updates """ class DeleteMarker(object): pass def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False): # Init base super(UpdateableZipFile, self).__init__(file, mode=mode, compression=compression, allowZip64=allowZip64) # track file to override in zip self._replace = {} # Whether the with statement was called self._allow_updates = False def writestr(self, zinfo_or_arcname, bytes, compress_type=None): if isinstance(zinfo_or_arcname, ZipInfo): name = zinfo_or_arcname.filename else: name = zinfo_or_arcname # If the file exits, and needs to be overridden, # mark the entry, and create a temp-file for it # we allow this only if the with statement is used if self._allow_updates and name in self.namelist(): temp_file = self._replace[name] = self._replace.get(name, tempfile.TemporaryFile()) temp_file.write(bytes) # Otherwise just act normally else: super(UpdateableZipFile, self).writestr(zinfo_or_arcname, bytes, compress_type=compress_type) def write(self, filename, arcname=None, compress_type=None): arcname = arcname or filename # If the file exits, and needs to be overridden, # mark the entry, and create a temp-file for it # we allow this only if the with statement is used if self._allow_updates and arcname in self.namelist(): temp_file = self._replace[arcname] = self._replace.get(arcname, tempfile.TemporaryFile()) with open(filename, "rb") as source: shutil.copyfileobj(source, temp_file) # Otherwise just act normally else: super(UpdateableZipFile, self).write(filename, arcname=arcname, compress_type=compress_type) def __enter__(self): # Allow updates self._allow_updates = True return self def __exit__(self, exc_type, exc_val, exc_tb): # call base to close zip file, organically try: super(UpdateableZipFile, self).__exit__(exc_type, exc_val, exc_tb) if len(self._replace) > 0: self._rebuild_zip() finally: # In case rebuild zip failed, # be sure to still release all the temp files self._close_all_temp_files() self._allow_updates = False def _close_all_temp_files(self): for temp_file in self._replace.itervalues(): if hasattr(temp_file, ''close''): temp_file.close() def remove_file(self, path): self._replace[path] = self.DeleteMarker() def _rebuild_zip(self): tempdir = tempfile.mkdtemp() try: temp_zip_path = os.path.join(tempdir, ''new.zip'') with ZipFile(self.filename, ''r'') as zip_read: # Create new zip with assigned properties with ZipFile(temp_zip_path, ''w'', compression=self.compression, allowZip64=self._allowZip64) as zip_write: for item in zip_read.infolist(): # Check if the file should be replaced / or deleted replacement = self._replace.get(item.filename, None) # If marked for deletion, do not copy file to new zipfile if isinstance(replacement, self.DeleteMarker): del self._replace[item.filename] continue # If marked for replacement, copy temp_file, instead of old file elif replacement is not None: del self._replace[item.filename] # Write replacement to archive, # and then close it (deleting the temp file) replacement.seek(0) data = replacement.read() replacement.close() else: data = zip_read.read(item.filename) zip_write.writestr(item, data) # Override the archive with the updated one shutil.move(temp_zip_path, self.filename) finally: shutil.rmtree(tempdir)

ejemplo de uso:

with UpdateableZipFile("C:/Temp/Test2.docx", "a") as o: # Overwrite a file with a string o.writestr("word/document.xml", "Some data") # exclude an exiting file from the zip o.remove_file("word/fontTable.xml") # Write a new file (with no conflict) to the zp o.writestr("new_file", "more data") # Overwrite a file with a file o.write(r"C:/Temp/example.png", "word/settings.xml")