2012-01-13 4 views
22

Я работаю в среде, где я не могу ничего сохранить на диске. Мне нужно иметь возможность извлекать tar-файлы и разархивировать их без сохранения на диск. Это, кажется, не в состоянии:Использование Python, как вы распаковываете чисто в памяти?

Я попытался это, но она подбрасывает ошибки:

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

Как описано в блоке кода выше, я получаю следующее отслеживающий на линии ошибки:

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

Вы получаете эту ошибку, потому что 'response.content' не является допустимым gzipped tar-файлом. – geoffspear

+0

Это имеет смысл: так как я могу превратить его в действительный gzipped tar-файл? – pydanny

+0

Работает для меня с действительный tar.gz, отправленный с localhost. Возможно, вы просто получите плохой архив. – codysoyland

ответ

10

Оказывается, проблема заключалась в том, что файл "data.tar.gz не был архив деготь Просто GZIP сжатый файл Поэтому я решил его:..

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

Спасибо всем, кто помог Шаг в!

+23

** Это не ответ на вопрос, поставленный в названии, поэтому он очень запутан для читателей, которые хотят решать подобные проблемы. ** – nealmcb

2

Это должно помочь

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

К сожалению, требование - это не доступ к диску. ;) – pydanny

+0

Проблема в том, что использование zip-файла там, где оно есть, несущественно, но вам нужно знать, какой файл находится в архиве, который вы ищете. – dartdog

15

Я подозреваю, что ошибка говорит вам, что формат файла tarf ile ошибочно. Попробуйте получить файл с wget и развяжите его в командной строке.

Другой вопрос о том, как остановить Python, записывая содержимое файла на диск, требует более пристального изучения API tarfile. Вместо того, чтобы звонить TarFile.extract(), мне кажется, вам нужно getnames(), которое вернет имя каждого члена в файле tar. Затем вы можете использовать extractfile, чтобы получить содержимое этого элемента:

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

Вот пример:

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

Да, tar -zxvf data.tar.gz выбрасывает ошибку «tar: Unrecognized archive format: Недопустимый тип файла или формат». Попытка выяснить, где все идет не так, потому что я могу открыть из окна, но не в командной строке. : P – pydanny

+0

Ясно, что у меня есть свои флаги неправильно. gzip -d data.tar.gz отлично работает. Теперь, пытаясь понять, почему tarfile не работает хорошо. – pydanny

+0

Это странно, потому что я использовал те же флаги, что и вы, и получил положительный результат ... – snim2

6

Вы могли бы попробовать то, что мы делали, когда дело с запросами + деготь: Используйте | чтобы открыть файл. См. http://docs.python.org/library/tarfile.html#tarfile.open.

Вы можете увидеть код на https://github.com/djeese/djeese-client/blob/master/djeese/commands/clonestatic.py#L53

В основном вы открыть архивный файл с помощью tarfile.open(mode='r|gz', fileobj=response.raw).

Это прекрасно работало для нас, и, надеюсь, для вас тоже.

+0

Пробовал это, но он потерпел неудачу, потому что клиент предоставлял gzip-файл, который делал вид tarfile. Проблема исправлена ​​с использованием чистого gzip-решения. :) – pydanny