2012-01-13 9 views
22

Sto lavorando in un ambiente in cui non posso salvare nulla sul disco. Devo essere in grado di estrarre i file tar e decomprimerli senza salvare su disco. Questo sembra fallire:Utilizzo di Python, come si scompone puramente in memoria?

Ho provato questo ma lancia errori:

# fetch.py 
from cStringIO import StringIO 
import requests 
url = "http://example.com/data.tar.gz" 
response = requests.get(url) 

# ERROR is thrown here. Error shown below 
tar = tarfile.open(mode= "r:gz", fileobj = StringIO(response.content)) 

# This SHOULD break as tar.extract() saves to disk. 
# Can't tell because of error on previous line of code. 
data = tar.extract() 

Come descritto nel blocco di codice di cui sopra ottengo il seguente traceback sulla linea di errore:

Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
    File "./importers/bestbuy_fetcher.py", line 23, in download_bestbuy_batch 
    tar = tarfile.open(mode= "r:gz", fileobj = StringIO(response.content)) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/tarfile.py", line 1662, in open 
    return func(name, filemode, fileobj, **kwargs) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/tarfile.py", line 1711, in gzopen 
    **kwargs) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/tarfile.py", line 1689, in taropen 
    return cls(name, mode, fileobj, **kwargs) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/tarfile.py", line 1568, in __init__ 
    self.firstmember = self.next() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/tarfile.py", line 2324, in next 
    raise ReadError(str(e)) 
ReadError: invalid header 
+0

Si sta verificando quell'errore perché 'response.content' non è un file tar gzippato valido. – geoffspear

+0

Che senso ha: come posso trasformarlo in un file tar gzippato valido? – pydanny

+0

Funziona per me con un tar.gz valido servito da localhost. Potresti ricevere un tarball errato. – codysoyland

risposta

10

scopre che il problema era che il file "data.tar.gz non era un archivio tar Basta un file compresso con gzip Così ho risolto con:..

# fetch.py 
from cStringIO import StringIO 
import gzip 
import requests 
# Called a 'tar' file but actually a gzip file. @#$%!!! 
url = "http://example.com/data.tar.gz" 
response = requests.get(url) 

results = gzip.GzipFile(fileobj=StringIO(response.content)) 

Grazie a tutti coloro che hanno contribuito pitch in!

+23

** Questa non è una risposta alla domanda posta nel titolo, quindi è molto confuso per i lettori che vogliono risolvere problemi simili. ** – nealmcb

2

Questo dovrebbe aiutare

import sys 
import zipfile 
sys.argv[0] = "/home/tom/Documents/REdata/AllListing1RES.zip" 
zip_file = zipfile.ZipFile(sys.argv[0]) 
items_file = zip_file.open('AllListing1RES.txt', 'rU') 
df = read_table(items_file, sep='\t', index_col=0) 
+2

Sfortunatamente, il requisito non è l'accesso al disco. ;) – pydanny

+0

Il problema è l'uso di zipfile dov'è, è irrilevante, ma è necessario sapere quale file si trova nell'archivio che si sta cercando. – dartdog

15

Ho il sospetto che l'errore ti stia dicendo che il formato del file del tarfile è sbagliato. Prova a scaricare il file con wget e decomprimilo sulla riga di comando.

L'altra domanda, su come impedire a Python di scrivere il contenuto del file su disco richiede uno sguardo più da vicino all'API tarfile. Invece di chiamare TarFile.extract() penso che sia necessario getnames() che restituirà il nome di ogni membro nel file tar. Quindi è possibile utilizzare extractfile per ottenere il contenuto del membro:

| extractfile(self, member) 
|  Extract a member from the archive as a file object. `member' may be 
|  a filename or a TarInfo object. If `member' is a regular file, a 
|  file-like object is returned. If `member' is a link, a file-like 
|  object is constructed from the link's target. If `member' is none of 
|  the above, None is returned. 
|  The file-like object is read-only and provides the following 
|  methods: read(), readline(), readlines(), seek() and tell() 

Ecco un esempio:

import tarfile  

# Open tarfile 
tar = tarfile.open(mode="r:gz", fileobj = file('foo.tgz')) 

# Iterate over every member 
for member in tar.getnames(): 
    # Print contents of every file 
    print tar.extractfile(member).read() 
+0

Sì, tar -zxvf data.tar.gz genera un errore "tar: formato di archivio non riconosciuto: tipo di file o formato non appropriato". Cercando di capire dove le cose stanno andando male perché posso aprire da una finestra ma non dalla riga di comando. : P – pydanny

+0

Chiaramente ho sbagliato le mie bandiere. gzip -d data.tar.gz funziona bene. Ora stiamo cercando di capire perché il tarfile di Python non sta giocando bene. – pydanny

+0

Questo è strano perché ho usato le stesse bandiere di te e ho ottenuto un risultato positivo ... – snim2

6

Si potrebbe provare quello che abbiamo fatto quando si tratta di richieste + tar: Utilizzare il | modalità per aprire il file. Vedi http://docs.python.org/library/tarfile.html#tarfile.open per i dettagli.

È possibile visualizzare il codice a https://github.com/djeese/djeese-client/blob/master/djeese/commands/clonestatic.py#L53

Fondamentalmente si apre il file tar usando tarfile.open(mode='r|gz', fileobj=response.raw).

Questo ha funzionato meravigliosamente per noi, e speriamo che faccia anche per voi.

+0

Provato ma non è riuscito perché il client stava fornendo un file gzip che faceva finta di essere un tarfile. Problema risolto utilizzando una soluzione gzip pura. :) – pydanny