2013-03-12 8 views
24

Je voudrais télécharger un fichier en utilisant urllib et décompresser le fichier en mémoire avant de l'enregistrer.Télécharger et décompresser un fichier gzippé en mémoire?

C'est ce que j'ai en ce moment:

response = urllib2.urlopen(baseURL + filename) 
compressedFile = StringIO.StringIO() 
compressedFile.write(response.read()) 
decompressedFile = gzip.GzipFile(fileobj=compressedFile, mode='rb') 
outfile = open(outFilePath, 'w') 
outfile.write(decompressedFile.read()) 

Cela finit par écrire des fichiers vides. Comment puis-je réaliser ce que je suis après?

Mise à jour Réponse:

#! /usr/bin/env python2 
import urllib2 
import StringIO 
import gzip 

baseURL = "https://www.kernel.org/pub/linux/docs/man-pages/" 
filename = "man-pages-3.34.tar.gz" 
outFilePath = filename[:-3] 

response = urllib2.urlopen(baseURL + filename) 
compressedFile = StringIO.StringIO(response.read()) 
decompressedFile = gzip.GzipFile(fileobj=compressedFile) 

with open(outFilePath, 'w') as outfile: 
    outfile.write(decompressedFile.read()) 
+0

ce qui ne va pas avec le disque de décompression? – MattDMo

+2

Je suis en train de décompresser sur le disque, ne laissant jamais les octets compressés toucher le disque. – OregonTrail

+0

Est-ce que 'compressedFile' obtient déjà des byes? – MattDMo

Répondre

35

Vous devez demander au début de compressedFile après avoir écrit, mais avant de passer à gzip.GzipFile(). Sinon, il sera lu à la fin par le module gzip et apparaîtra sous forme de fichier vide. Voir ci-dessous:

#! /usr/bin/env python 
import urllib2 
import StringIO 
import gzip 

baseURL = "https://www.kernel.org/pub/linux/docs/man-pages/" 
filename = "man-pages-3.34.tar.gz" 
outFilePath = "man-pages-3.34.tar" 

response = urllib2.urlopen(baseURL + filename) 
compressedFile = StringIO.StringIO() 
compressedFile.write(response.read()) 
# 
# Set the file's current position to the beginning 
# of the file so that gzip.GzipFile can read 
# its contents from the top. 
# 
compressedFile.seek(0) 

decompressedFile = gzip.GzipFile(fileobj=compressedFile, mode='rb') 

with open(outFilePath, 'w') as outfile: 
    outfile.write(decompressedFile.read()) 
+4

Il s'avère que j'aurais pu profiter de '__init__' de StringIO, voir la question mise à jour. – OregonTrail

+0

Oui. Cela fonctionne encore mieux. :) Je laisserai ma réponse non éditée puisque vous avez déjà ajouté la réponse mise à jour. Merci. – crayzeewulf

+0

@OregonTrail: ou vous pouvez supprimer l'intermédiaire et [passer directement la réponse] (http://stackoverflow.com/a/26435241/4279). btw, ne mettez pas de * réponses * dans la question; [vous êtes encouragé à poster votre propre réponse] (http://stackoverflow.com/help/self-answer). – jfs

9

Pour ceux qui utilisent Python 3, la réponse équivalente est:

import urllib.request 
import io 
import gzip 

response = urllib.request.urlopen(FILE_URL) 
compressed_file = io.BytesIO(response.read()) 
decompressed_file = gzip.GzipFile(fileobj=compressed_file) 

with open(OUTFILE_PATH, 'wb') as outfile: 
    outfile.write(decompressed_file.read()) 
+0

cela ne fonctionnera pas: vous essayez d'écrire des octets dans un fichier texte; utilisez le mode binaire à la place. Essayez: 'copyfileobj (GzipFile (fileobj = réponse), open (chemin_fichier, 'wb'))' – jfs

6

Si vous avez Python 3.2 ou au-dessus, la vie serait beaucoup plus facile:

#!/usr/bin/env python3 
import gzip 
import urllib.request 

baseURL = "https://www.kernel.org/pub/linux/docs/man-pages/" 
filename = "man-pages-4.03.tar.gz" 
outFilePath = filename[:-3] 

response = urllib.request.urlopen(baseURL + filename) 
with open(outFilePath, 'wb') as outfile: 
    outfile.write(gzip.decompress(response.read())) 

Pour ceux qui s'intéressent à l'histoire, voir https://bugs.python.org/issue3488 et https://hg.python.org/cpython/rev/3fa0a9553402.

-2

Un code de ligne pour imprimer le contenu du fichier décompressé:

print gzip.GzipFile(fileobj=StringIO.StringIO(urllib2.urlopen(DOWNLOAD_LINK).read()), mode='rb').read() 
Questions connexes