2010-05-27 7 views
5

En algunas pruebas de unidades Python de un programa en el que estoy trabajando utilizamos archivos comprimidos en memoria para pruebas de extremo a extremo. En SetUp() creamos un archivo zip simple, pero en algunas pruebas queremos sobrescribir algunos archivos. Para esto hacemos "zip.writestr (archive_name, zip.read (archive_name) + new_content)". Algo así comoA Python 2.6 no le gusta anexar archivos existentes en archivos zip

import zipfile 
from StringIO import StringIO 

def Foo(): 
    zfile = StringIO() 
    zip = zipfile.ZipFile(zfile, 'a') 
    zip.writestr(
     "foo", 
     "foo content") 
    zip.writestr(
     "bar", 
     "bar content") 
    zip.writestr(
     "foo", 
     zip.read("foo") + 
     "some more foo content") 
    print zip.read("bar") 

Foo() 

El problema es que esto funciona bien en Python 2.4 y 2.5, pero no 2.6. En Python 2.6 esto falla en la línea de impresión con "BadZipfile: nombre de archivo en el directorio" bar "y el encabezado" foo "difiere".

Parece que está leyendo la barra de archivos correcta, pero cree que debería leer foo en su lugar.

Estoy perdido. ¿Qué estoy haciendo mal? ¿Esto no es compatible? Traté de buscar en la web, pero no pude encontrar problemas similares. Leí la documentación del archivo zip, pero no pude encontrar nada (que yo pensara que era) relevante, especialmente porque estoy llamando a read() con la cadena del nombre del archivo.

¿Alguna idea?

¡Gracias de antemano!

Respuesta

2

El archivo PKZIP es altamente estructurado y simplemente agregarlo al final lo arruinará. No puedo hablar con versiones anteriores que funcionen, pero la solución a este problema es abrir un archivo zip para leer, abrir uno nuevo para escribir, extraer el contenido del primero y luego agregar los componentes adicionales al final. Cuando se complete, reemplace el archivo zip original con el archivo recién creado.

El rastreo consigo cuando se ejecuta su código cuando se ejecuta su código es:

Traceback (most recent call last): 
    File "zip.py", line 19, in <module> 
    Foo() 
    File "zip.py", line 17, in Foo 
    print zip.read("bar") 
    File "/usr/lib/python2.6/zipfile.py", line 834, in read 
    return self.open(name, "r", pwd).read() 
    File "/usr/lib/python2.6/zipfile.py", line 874, in open 
    zinfo.orig_filename, fname) 
zipfile.BadZipfile: File name in directory "bar" and header "foo" differ. 

Tras una inspección más cercana, Me he dado cuenta de que usted está leyendo desde un StringIO tipo fichero abierto con el 'modo a'ppend que debería da como resultado un error de lectura ya que 'a' no es generalmente legible, y ciertamente debe buscarse() ed entre lecturas y escrituras. Voy a engañar a algunos y actualizar esto.

Actualización:

haber robado casi todo de este código de Doug Hellmann excelente Python Module of the Week, me parece que funciona más o menos como esperaba. Uno no puede simplemente anexar a un archivo de PKZIP estructurada, y si el código en el post original nunca hizo el trabajo, fue por accidente:

import zipfile 
import datetime 

def create(archive_name): 
    print 'creating archive' 
    zf = zipfile.ZipFile(archive_name, mode='w') 
    try: 
     zf.write('/etc/services', arcname='services') 
    finally: 
     zf.close() 

def print_info(archive_name): 
    zf = zipfile.ZipFile(archive_name) 
    for info in zf.infolist(): 
     print info.filename 
     print '\tComment:\t', info.comment 
     print '\tModified:\t', datetime.datetime(*info.date_time) 
     print '\tSystem:\t\t', info.create_system, '(0 = Windows, 3 = Unix)' 
     print '\tZIP version:\t', info.create_version 
     print '\tCompressed:\t', info.compress_size, 'bytes' 
     print '\tUncompressed:\t', info.file_size, 'bytes' 
     print 
    zf.close() 

def append(archive_name): 
    print 'appending archive' 
    zf = zipfile.ZipFile(archive_name, mode='a') 
    try: 
     zf.write('/etc/hosts', arcname='hosts') 
    finally: 
     zf.close() 

def expand_hosts(archive_name): 
    print 'expanding hosts' 
    zf = zipfile.ZipFile(archive_name, mode='r') 
    try: 
     host_contents = zf.read('hosts') 
    finally: 
     zf.close 

    zf = zipfile.ZipFile(archive_name, mode='a') 
    try: 
     zf.writestr('hosts', host_contents + '\n# hi mom!') 
    finally: 
     zf.close() 

def main(): 
    archive = 'zipfile.zip' 
    create(archive) 
    print_info(archive) 
    append(archive) 
    print_info(archive) 
    expand_hosts(archive) 
    print_info(archive) 

if __name__ == '__main__': main() 

Notable es la salida desde la última llamada a print_info:

... 
hosts 
    Modified: 2010-05-20 03:40:24 
    Compressed: 404 bytes 
    Uncompressed: 404 bytes 

hosts 
    Modified: 2010-05-27 11:46:28 
    Compressed: 414 bytes 
    Uncompressed: 414 bytes 

No se agregó a los 'hosts' de arcname existentes, creó un miembro de archivo adicional.

"Je N'ai fait celle-ci plus longue Que parce que je n'ai pas eu le loisir de La faire más courte".
- Blaise Pascal formato de archivo

0

La postal está diseñado para ser añadido al.Puede agregar archivos adicionales con el mismo nombre, y extraerá el último, pero ZipFile no está diseñado para leer y escribir al mismo tiempo. Debe cerrar el archivo para escribir los registros finales (https://hg.python.org/cpython/file/2.7/Lib/zipfile.py#l1263) que luego se vuelven a leer por el método open() o read(). (https://hg.python.org/cpython/file/2.7/Lib/zipfile.py#l933)

import zipfile 
from StringIO import StringIO 

def Foo(): 
    zfile = StringIO() 

    zip = zipfile.ZipFile(zfile, 'a') 
    zip.writestr(
     "foo", 
     "foo content") 
    zip.writestr(
     "bar", 
     "bar content") 
    zip.close() 

    zip = zipfile.ZipFile(zfile, 'r') 
    foo_content = zip.read("foo") 

    zip2 = zipfile.ZipFile(zfile, 'a') 
    zip2.writestr(
     "foo", 
     foo_content + 
     "some more foo content") 
    print zip2.namelist() 
    print zip2.read("bar") 

Foo() 

de salida:

pyzip.py:23: UserWarning: Duplicate name: 'foo' 
    "some more foo content") 
['foo', 'bar', 'foo'] 
bar content 
Cuestiones relacionadas