Скачать и распаковать сжатый файл в памяти?

Я хотел бы загрузить файл с помощью urllib и распаковать файл в памяти перед сохранением.

Это то, что у меня есть прямо сейчас:

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())

Это заканчивается записью пустых файлов. Как я могу достичь того, что я после?

Обновленный ответ:

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

baseURL = "https://www.kernel.org/pub/linux/docs/man-pages/"        
# check filename: it may change over time, due to new updates
filename = "man-pages-5.00.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())

person OregonTrail    schedule 12.03.2013    source источник
comment
что не так с распаковкой на диск?   -  person MattDMo    schedule 12.03.2013
comment
Я распаковываю на диск, просто никогда не позволяя сжатым байтам касаться диска.   -  person OregonTrail    schedule 12.03.2013
comment
compressedFile когда-нибудь прощается?   -  person MattDMo    schedule 12.03.2013
comment
Да, в обновленной версии   -  person OregonTrail    schedule 28.02.2014
comment
несвязанный: вы можете использовать shutil.copyfileobj(decompressed_file, outfile), чтобы сохранить файл по частям, не загружая его в память.   -  person jfs    schedule 11.06.2015


Ответы (4)


Вам нужно искать начало compressedFile после записи в него, но перед передачей в gzip.GzipFile(). В противном случае он будет прочитан с конца модулем gzip и будет отображаться для него как пустой файл. Смотри ниже:

#! /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())
person crayzeewulf    schedule 12.03.2013
comment
Оказывается, я мог бы воспользоваться __init__ StringIO, см. обновленный вопрос. - person OregonTrail; 12.03.2013
comment
Да. Это работает даже лучше. :) Я оставлю свой ответ без изменений, так как вы уже добавили обновленный ответ. Спасибо. - person crayzeewulf; 12.03.2013
comment
@OregonTrail: или вы можете исключить посредника и пройти response напрямую. Кстати, не добавляйте ответы в вопрос; рекомендуется опубликовать собственный ответ. - person jfs; 11.06.2015

Для тех, кто использует Python 3, эквивалентный ответ:

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())
person lyschoening    schedule 09.02.2015
comment
это не сработает: вы пытаетесь записать байты в текстовый файл; вместо этого используйте двоичный режим. Попробуйте: copyfileobj(GzipFile(fileobj=response), open(outfile_path, 'wb')) - person jfs; 11.06.2015

Если у вас Python 3.2 или выше, жизнь будет намного проще:

#!/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()))

Для тех, кто интересуется историей, см. https://bugs.python.org/issue3488 и https://hg.python.org/cpython/rev/3fa0a9553402.

person Chih-Hsuan Yen    schedule 05.12.2015

Однострочный код для печати содержимого распакованного файла:

print gzip.GzipFile(fileobj=StringIO.StringIO(urllib2.urlopen(DOWNLOAD_LINK).read()), mode='rb').read()
person BaiJiFeiLong    schedule 02.03.2017