2013-02-08 2 views
2

Я пытаюсь прочитать только один файл из файла tar.gz. Все операции над объектом файла обработан работает отлично, но когда я прочитал от конкретного члена, всегда StreamError поднимается, проверьте этот код:read() из ExFileObject всегда вызывает исключение StreamError

import tarfile 
fd = tarfile.open('file.tar.gz', 'r|gz') 
for member in fd.getmembers(): 
    if not member.isfile(): 
     continue 
    cfile = fd.extractfile(member) 
    print cfile.read() 
    cfile.close() 
fd.close() 

cfile.read() всегда вызывает «tarfile.StreamError: поиск в обратном направлении не допускается»

мне нужно прочитать содержимое MEM, не демпинг в файл (extractall работает отлично)

Спасибо!

+1

Есть ли причина, что демпинг в файл не будет работать? Вы можете использовать, например, 'tempfile.mkdtemp', чтобы создать каталог, извлечь его, прочитать нужные файлы и затем удалить каталог. Если у вас нет доступа к любой файловой системе, доступной для записи, или вы пробовали это, и производительность неприемлема, я не могу думать о какой-либо другой причине, чтобы ее исключить. – abarnert

+0

'extractall' в директорию' tmp' – jmunsch

ответ

7

Проблема эта линия:

fd = tarfile.open('file.tar.gz', 'r|gz') 

Вы не хотите 'r|gz', вы хотите 'r:gz'.

Если я запускаю ваш код на тривиальном tarball, я могу даже распечатать member и посмотреть test/foo, а затем я получаю ту же самую ошибку на read, которую вы получите.

Если я исправлю его, чтобы использовать 'r:gz', он работает.

От the docs:

mode has to be a string of the form 'filemode[:compression]'

...

For special purposes, there is a second format for mode: 'filemode|[compression]'. tarfile.open() will return a TarFile object that processes its data as a stream of blocks. No random seeking will be done on the file… Use this variant in combination with e.g. sys.stdin, a socket file object or a tape device. However, such a TarFile object is limited in that it does not allow to be accessed randomly, see Examples.

'r|gz' предназначен для того, когда у вас есть, не доступный для поиска потока, и он обеспечивает только подмножество операций. К сожалению, похоже, что не указано, какие операции разрешены, и ссылка на примеры не помогает, потому что ни один из примеров не использует эту функцию. Таким образом, вы должны либо прочитать the source, либо выяснить это через пробную версию и ошибку.

Но, поскольку у вас есть нормальный файл для поиска, вам не нужно беспокоиться об этом; просто используйте 'r:gz'.

0

В дополнение к файловому режиму, я попытался установить seek на сетевой поток.

У меня была такая же ошибка при попытке requests.get файла, поэтому я извлек все директории TMP:

# stream == requests.get 
inputs = [tarfile.open(fileobj=LZMAFile(stream), mode='r|')] 
t = "/tmp" 
for tarfileobj in inputs:   
    tarfileobj.extractall(path=t, members=None) 
for fn in os.listdir(t): 
    with open(os.path.join(t, fn)) as payload: 
     print(payload.read()) 
Смежные вопросы