2011-11-28 10 views
9

devo capire come scrivere output di file in un file compresso in Python, simile ai due-liner di seguito:pitone equivalente di output di file tubazioni a gzip in Perl usando un tubo

open ZIPPED, "| gzip -c > zipped.gz"; 
print ZIPPED "Hello world\n"; 

In Perl , questo usa Unix gzip per comprimere tutto ciò che si stampa nel filehandle ZIPPED nel file "zipped.gz".

so come usare "importazione gzip" per fare questo in Python come questo:

import gzip 
zipped = gzip.open("zipped.gz", 'wb') 
zipped.write("Hello world\n") 

Tuttavia, che è estremamente lento. Secondo il profiler, l'utilizzo di tale metodo richiede il 90% del tempo di esecuzione poiché sto scrivendo 200 GB di dati non compressi su vari file di output. Sono consapevole che il file system potrebbe essere parte del problema qui, ma voglio escluderlo usando invece la compressione Unix/Linux. Questo è in parte perché ho sentito che la decompressione usando questo stesso modulo è altrettanto lenta.

+1

Avete bisogno di farlo fare in puro Python, o potrebbe accontentarsi di una chiamata in una binario sul filesystem (in Python, utilizza il modulo sottoprocesso)? – ChristopheD

+0

Preferisco non farlo in Python poiché i metodi Python sono troppo lenti. – bu11d0zer

+0

Hai eseguito il programma gzip dalla shell su 200 GB di dati non compressi? Mi aspetto che ci vorrà un bel po 'di tempo per il wall-lock con il 90-100% di utilizzo della CPU - sulla mia scatola di Windows funziona circa 1 minuto per GB, mentre il modulo gzip di Python richiede circa 2 minuti per GB. – Dave

risposta

10

Il suggerimento di ChristopheD di utilizzare subprocess module è una risposta appropriata a questa domanda. Tuttavia, non è chiaro per me che risolverà i tuoi problemi di prestazioni. Dovresti misurare le prestazioni del nuovo codice per essere sicuro.

per convertire il vostro codice di esempio:

import subprocess 

p = subprocess.Popen("gzip -c > zipped.gz", shell=True, stdin=subprocess.PIPE) 
p.communicate("Hello World\n") 

Dal momento che avete bisogno di inviare grandi quantità di dati al sub-processo, si consiglia di utilizzare l'attributo stdin dell'oggetto Popen. Per esempio:

import subprocess 

p = subprocess.Popen("gzip -c > zipped.gz", shell=True, stdin=subprocess.PIPE) 
p.stdin.write("Some data") 

# Write more data here... 

p.communicate() # Finish writing data and wait for subprocess to finish 

È inoltre possibile trovare la discussione a this question utile.

+0

Ho verificato che questo metodo è il 33% più veloce su un file altamente comprimibile da 1 GB. Questo è un bel miglioramento rispetto a gzip.open. Ecco il codice che ho usato per provarlo: importazione di testo sottoprocesso = "fjlaskfjioewru oijf alksfjlkqs jr jweqoirjwoiefjlkadsfj afjf \ n" for i in xrange (1,25): text + = testo p = subprocess.Popen ("gzip -c> zipped.gz", shell = True, stdin = subprocess.PIPE) ' p.stdin.write (testo) p.communicate() Tempo per gzip.aprire: 12.109u 1.194s 0: 13.37 99,4% 0 + 0 + 0k 0io 0PF + 0w Tempo per il codice precedente: 8.379u 2.602s 0: 10,17 107,8% 0 + 0 + 0k 0io 0PF + 0w – bu11d0zer

+0

Questo è una buona e completa risposta alla mia domanda. Grazie. – bu11d0zer

+0

Assicurati di accettare la tua risposta preferita :-). A tutti noi piace il rappresentante extra. – Dave

2

Utilizzando la gzip module è il funzionario di sola andata-to-do-it ed è improbabile che qualsiasi altro approccio pitone puro andrà più veloce. Ciò è particolarmente vero perché la dimensione dei dati esclude le opzioni in memoria. Molto probabilmente, il modo più veloce è scrivere il file completo sul disco e usare subprocess per chiamare gz su quel file.

4

provare qualcosa di simile:

from subprocess import Popen, PIPE 
f = open('zipped.gz', 'w') 
pipe = Popen('gzip', stdin=PIPE, stdout=f) 
pipe.communicate('Hello world\n') 
f.close() 
+0

Questa risposta è anche buona e funziona bene. – bu11d0zer