2010-12-03 2 views
2

Это мое первое сообщение о переполнении стека, у меня есть вопрос об извлечении одного файла из файла TAR с использованием сжатия GZ. Я не лучший на Python, поэтому я могу сделать это неправильно, любая помощь будет очень оценена.Обработка одиночного файла из поврежденного GZ (TAR)


Сценарий:

Поврежденный * .tar.gz файл входит, первый файл в ГЗ содержит важную информацию для получения SN системы. Это можно использовать для идентификации машины, чтобы мы могли отправить уведомление администратору о том, что файл был поврежден.

Проблема:

Использование регулярных UNIX дегтя бинарного Я могу извлечь только файл README из архива, даже если архив не является полным и будет возвращать ошибку при полностью извлекая его. Однако в Python я не могу извлечь только один файл, он всегда возвращает исключение, даже если я указываю только один файл.

Текущий Обход:

Я использую «os.popen» использовать деготь бинарного UNIX для того, чтобы получить только файл README.

Желаемая Решение:

Чтобы использовать пакет Python файл обработан, чтобы извлечь только один файл.

Пример ошибки:

UNIX (работы):

[[email protected] tmp]# tar -xvzf bundle.tar.gz README 
README 

gzip: stdin: unexpected end of file 
tar: Unexpected EOF in archive 
tar: Error is not recoverable: exiting now 
[[email protected] tmp]# 
[[email protected] tmp]# ls 
bundle.tar.gz README 

Python:

>>> import tarfile 
>>> tar = tarfile.open("bundle.tar.gz") 
>>> data = tar.extractfile("README").read() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
    File "/usr/lib64/python2.4/tarfile.py", line 1364, in extractfile 
    tarinfo = self.getmember(member) 
    File "/usr/lib64/python2.4/tarfile.py", line 1048, in getmember 
    tarinfo = self._getmember(name) 
    File "/usr/lib64/python2.4/tarfile.py", line 1762, in _getmember 
    members = self.getmembers() 
    File "/usr/lib64/python2.4/tarfile.py", line 1059, in getmembers 
    self._load()  # all members, we first have to 
    File "/usr/lib64/python2.4/tarfile.py", line 1778, in _load 
    tarinfo = self.next() 
    File "/usr/lib64/python2.4/tarfile.py", line 1588, in next 
    self.fileobj.seek(self.offset) 
    File "/usr/lib64/python2.4/gzip.py", line 377, in seek 
    self.read(1024) 
    File "/usr/lib64/python2.4/gzip.py", line 225, in read 
    self._read(readsize) 
    File "/usr/lib64/python2.4/gzip.py", line 273, in _read 
    self._read_eof() 
    File "/usr/lib64/python2.4/gzip.py", line 309, in _read_eof 
    raise IOError, "CRC check failed" 
IOError: CRC check failed 
>>> print data 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
NameError: name 'data' is not defined 

Python (Обработка исключений):

>>> tar = tarfile.open("bundle.tar.gz") 
>>> try: 
...  data = tar.extractfile("README").read() 
... except: 
...  pass 
... 
>>> print(data) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in ? 
NameError: name 'data' is not defined 
+1

Глядя на tarfile.py код, extractfile вызывает getmember, который в конечном итоге вызывает getmembers. getmembers сканирует весь файл tar, который сжимает gzip, когда он попадает в EOF/Corrupted и т. д. Попробуйте предоставить уже распакованный поток, чтобы исключение crc не было выбрано внутри вашего извлечения. – kevpie 2010-12-04 04:32:32

ответ

0

Используя ручной метод Unix, похоже, что gzip распаковывает файл до той точки, где он ломается.

Модуль Python gzip (или tar) выходит, как только он замечает, что у вас есть поврежденный архив из-за неудачной проверки CRC.

Просто идея, но вы можете предварительно обработать поврежденные архивы с помощью gzip и повторно сжать их, чтобы исправить CRC.

gunzip < damaged.tar.gz | gzip > corrected.tar.gz 

Это даст вам corrected.tar.gz, который теперь будет содержать все данные до того момента, когда архив был разбит. Теперь вы можете использовать библиотеку python tar/gzip, не получая исключения CRC.

Имейте в виду, что эта команда будет un-gzip и gzip архивом, который требует хранения IO и процессорного времени, и вы не должны делать это для всех ваших архивов.

Для того, чтобы быть эффективными, вы должны запускать его только в том случае, если вы получите ошибку IOError: CRC.

0

Вы можете сделать что-то вроде этого - попытайтесь распаковать gzip-файл во временный файл, а затем попытайтесь извлечь из него магический файл. В следующем примере я довольно агрессивно отношусь к попытке прочитать весь файл - в зависимости от размера блока gzipped-данных вы, вероятно, избегаете чтения с максимальным значением 128-256k. Моя кишка говорит мне, что gzip работает максимум в 64 тыс. Блоков, но я не обещаю.

Этот метод делает все в памяти, не требуя промежуточных файлов/записи на диск, но он также сохраняет весь объем распакованных данных в памяти. Я не шучу о тонкой настройке этого для вашего конкретного использования -дело.

#!/usr/bin/python 

import gzip 
import tarfile 
import StringIO 

# Depending on how your tar file is constructed, you might need to specify 
# './README' as your magic_file 

magic_file = 'README' 

f = gzip.open('corrupt', 'rb') 

t = StringIO.StringIO() 

try: 
    while 1: 
     block = f.read(1024) 
     t.write(block) 
except Exception as e: 
    print str(e) 
    print '%d bytes decompressed' % (t.tell()) 

t.seek(0) 
tarball = tarfile.TarFile.open(name=None, mode='r', fileobj=t) 

try: 
    magic_data = tarball.getmember(magic_file).tobuf() 
    # I didn't actually try this part, but in theory 
    # getmember returns a tarinfo object which you can 
    # use to extract the file 

    # search magic data for serial number or print out the 
    # file 
    print magic_data 
except Exception as e: 
    print e 
Смежные вопросы