cargar un archivo pickle desde un archivo zip

Por alguna razón no puedo hacer que cPickle.load funcione en el objeto de tipo de archivo devuelto por ZipFile.open (). Si llamo a read () en el objeto de tipo de archivo devuelto por ZipFile.open () puedo usar cPickle.loads sin embargo.

Ejemplo ….

import zipfile import cPickle # the data we want to store some_data = {1: 'one', 2: 'two', 3: 'three'} # # create a zipped pickle file # zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED) zf.writestr('data.pkl', cPickle.dumps(some_data)) zf.close() # # cPickle.loads works # zf = zipfile.ZipFile('zipped_pickle.zip', 'r') sd1 = cPickle.loads(zf.open('data.pkl').read()) zf.close() # # cPickle.load doesn't work # zf = zipfile.ZipFile('zipped_pickle.zip', 'r') sd2 = cPickle.load(zf.open('data.pkl')) zf.close() 

Nota: no quiero comprimir solo el archivo pickle sino muchos archivos de otros tipos. Esto es solo un ejemplo.

Se debe a una imperfección en el objeto pseudofile implementado por el módulo zipfile (para el método .open de la clase ZipFile introducido en Python 2.6). Considerar:

 >>> f = zf.open('data.pkl') >>> f.read(1) '(' >>> f.readline() 'dp1\n' >>> f.read(1) '' >>> 

la secuencia de .read(1).readline() es lo que hace .loads internamente (en un pickle protocolo-0, el valor predeterminado en Python 2, que es lo que estás usando aquí). Desafortunadamente, la imperfección de zipfile significa que esta secuencia en particular no funciona, produciendo un “final de archivo” espurio (.read devolviendo una cadena vacía) justo después del primer par readline / readline.

No estoy seguro de si este error en la biblioteca estándar de Python está arreglado en Python 2.7 – Lo voy a comprobar.

Edición : recién comprobado: el error se corrigió en Python 2.7 rc1 (el candidato de lanzamiento que actualmente es la última versión 2.7). Todavía no sé si también se ha corregido en la última versión de corrección de errores de 2.6.

Vuelva a editar : el error aún está allí en Python 2.6.5, la última versión de Python 2.6 para corregir errores, por lo que si no puede actualizar a 2.7 y necesita objetos de ZipFile.open mejor comportamiento de ZipFile.open , un backport de La solución 2.7 parece la única solución viable.

Tenga en cuenta que no es seguro que necesite objetos pseudofiles de mejor comportamiento; Si controla las llamadas de volcado y puede usar el protocolo más reciente y mejor, todo estará bien:

 >>> zf = zipfile.ZipFile('zipped_pickle.zip', 'w', zipfile.ZIP_DEFLATED) >>> zf.writestr('data.pkl', cPickle.dumps(some_data, -1)) >>> sd2 = cPickle.load(zf.open('data.pkl')) >>> 

es solo el antiguo “protocolo 0” compatible con versiones anteriores (el valor predeterminado) que requiere un comportamiento adecuado de objetos pseudofílicos cuando se mezclan las llamadas de lectura y de línea de lectura en la load (el protocolo 0 también es más lento y produce pickles más grandes, por lo que definitivamente no se recomienda a menos que sea al revés la compatibilidad con las versiones antiguas de Python, o la naturaleza solo ascii de los encurtidos que produce 0, son restricciones obligatorias en su aplicación).