example create python gzip subprocess gunzip

create - gzip python example



Una forma más limpia de leer/gunzip un archivo enorme en python (2)

Así que tengo algunos archivos .gz bastante gigantescos: estamos hablando de 10 a 20 gb cada uno cuando se descomprimen.

Necesito recorrer cada línea de ellos, así que estoy usando el estándar:

import gzip f = gzip.open(path+myFile, ''r'') for line in f.readlines(): #(yadda yadda) f.close()

Sin embargo, los comandos open() y close() toman AGES, usando hasta el 98% de la memoria + CPU. Tanto es así que el programa sale e imprime Killed to the terminal. ¿Tal vez está cargando todo el archivo extraído en la memoria?

Ahora estoy usando algo como:

from subprocess import call f = open(path+''myfile.txt'', ''w'') call([''gunzip'', ''-c'', path+myfile], stdout=f) #do some looping through the file f.close() #then delete extracted file

Esto funciona. ¿Pero hay una forma más limpia?


Echa un vistazo a los pandas, en particular las herramientas IO . Son compatibles con la compresión gzip al leer archivos y puede leer archivos en trozos. Además, los pandas son muy rápidos y eficientes en la memoria.

Como nunca lo intenté, no sé qué tan bien viven juntos la compresión y la lectura en fragmentos, pero podría valer la pena intentarlo.


Estoy 99% seguro de que su problema no está en gzip.open() , sino en readlines() .

Como explica la documentación :

f.readlines () devuelve una lista que contiene todas las líneas de datos en el archivo.

Obviamente, eso requiere leer leer y descomprimir todo el archivo, y construir una lista absolutamente gigantesca.

Lo más probable es que, en realidad, las llamadas a malloc para asignar toda esa memoria se lleven para siempre. Y luego, al final de este alcance (asumiendo que estás usando CPython), tiene que GC toda esa lista gigantesca, que también durará para siempre.

Casi nunca quieres usar readlines . A menos que estés usando un Python muy antiguo, haz esto:

for line in f:

Un file es un iterable lleno de líneas, al igual que la list devuelta por las líneas de lectura. Excepto que en realidad no es una list , genera más líneas sobre la marcha mediante la lectura de un búfer. Por lo tanto, en un momento dado, solo tendrá una línea y un par de búferes del orden de 10 MB cada uno, en lugar de una list 25 GB. Y la lectura y la descompresión se extenderán a lo largo de la vida útil del bucle, en lugar de hacerlo de una vez.

Desde una prueba rápida, con un archivo gzip de gzip.open() , gzip.open() es efectivamente instantáneo, for line in f: pass toma unos segundos, gzip.close() es efectivamente instantánea. Pero si hago for line in f.readlines(): pass , me toma ... bueno, no estoy seguro de cuánto tiempo, porque después de un minuto mi sistema entró en el infierno y tuve que matar al intérprete haz que responda a cualquier cosa ...

Dado que esto ha surgido una docena de veces más desde esta respuesta, escribí esta publicación del blog que explica un poco más.