2009-02-04 24 views
30

La única forma en que surgió para eliminar un archivo de un archivo comprimido fue crear un archivo zip temporal sin el archivo que se debe eliminar y luego cambiarle el nombre al nombre del archivo original.Eliminar archivo del archivo zip con el Módulo ZipFile

En Python 2.4, la clase ZipInfo tenía un atributo file_offset, por lo que era posible crear un segundo archivo comprimido y copiar los datos en otro archivo sin descomprimir/recomprimir.

file_offset falta en python 2.6, ¿hay otra opción que crear otro archivo comprimido al descomprimir cada archivo y volver a comprimirlo otra vez?

¿Existe alguna forma directa de eliminar un archivo en el archivo comprimido, busqué y no encontré nada?

+0

encontré este hilo en el seguimiento de errores de Python discutir las dificultades de la eliminación de archivos desde un archivo zip: https: //bugs.python. org/issue6818 –

Respuesta

34

El siguiente fragmento trabajó para mí (borra todos los archivos * .exe desde un archivo Zip):

zin = zipfile.ZipFile ('archive.zip', 'r') 
zout = zipfile.ZipFile ('archve_new.zip', 'w') 
for item in zin.infolist(): 
    buffer = zin.read(item.filename) 
    if (item.filename[-4:] != '.exe'): 
     zout.writestr(item, buffer) 
zout.close() 
zin.close() 

Si usted lee todo en la memoria, se puede eliminar la necesidad de un segundo archivo. Sin embargo, este fragmento recomprime todo.

Después de una inspección más cercana, el ZipInfo.header_offset es el desplazamiento desde el inicio del archivo. El nombre es engañoso, pero el encabezado Zip principal en realidad se almacena al final del archivo. Mi editor hexadecimal lo confirma.

Así que el problema que se encontrará es el siguiente: También debe eliminar la entrada del directorio en el encabezado principal o apuntará a un archivo que ya no existe. Dejar el encabezado principal intacto podría funcionar si mantiene el encabezado local del archivo que está eliminando también, pero no estoy seguro de eso. ¿Cómo lo hiciste con el módulo anterior?

Sin modificar el encabezado principal me sale un error "falta X bytes en el archivo zip" cuando lo abro. This podría ayudarlo a descubrir cómo modificar el encabezado principal.

+0

gracias, pero si no estoy equivocado, cuando le eches un vistazo a zipfile.writestr verás que esto es solo una recompresión. Sería mucho más rápido simplemente copiar los archivos ya comprimidos sin descomprimirlos y luego comprimirlos nuevamente. – RSabet

+0

@RSabt Estoy de acuerdo con mdm que el descomprimir y reescribir es la única opción viable hasta el momento. Por cierto, quiero señalar que el código de mdm ayuda, pero mejor usar os.path.splitext() cuando vas a hacer algo más en serio. – RayLuo

+1

+1 para el nombre var zin zout = D –

0

La rutina delete_from_zip_file de ruamel.std.zipfile ¹ le permite eliminar un archivo basado en su ruta completa dentro del ZIP, o según patrones (re). P.ej. puede eliminar todos los archivos de .exetest.zip usando

from ruamel.std.zipfile import delete_from_zip_file 

delete_from_zip_file('test.zip', pattern='.*.exe') 

(tenga en cuenta el punto antes de la *).

Esto funciona de manera similar a la solución de mdm (incluida la necesidad de recompresión), pero recrea el archivo ZIP en memoria (utilizando la clase InMemZipFile()), sobrescribiendo el archivo anterior una vez que se ha leído por completo.


¹ responsabilidad: yo soy el autor de ese paquete.

2

No es muy elegante, pero esto es cómo lo hice:

import subprocess 
import zipfile 

z = zipfile.ZipFile(zip_filename) 

files_to_del = filter(lambda f: f.endswith('exe'), z.namelist()] 

cmd=['zip', '-d', zip_filename] + files_to_del 
subprocess.check_call(cmd) 

# reload the modified archive 
z = zipfile.ZipFile(zip_filename) 
+0

Esto es lo que terminé haciendo. Feo, pero 'ZipFile' simplemente no parece tener una forma de eliminar o actualizar/reemplazar archivos. – ArtOfWarfare

Cuestiones relacionadas