从损坏的GZ(TAR)处理单个文件提取

时间:2010-12-03 22:19:05

标签: python

这是我关于Stack Overflow的第一篇文章,我有一个关于使用GZ压缩从TAR文件中提取单个文件的问题。我不是最好的Python所以我可能做错了,任何帮助将不胜感激。


情境:

损坏的* .tar.gz文件进来,GZ中的第一个文件包含获取系统SN的重要信息。这可以用于识别机器,以便我们可以向管理员发出文件已损坏的通知。

问题

使用常规UNIX tar二进制文件,即使存档未完成,我也只能从存档中提取README文件,并且在完全提取存档时会返回错误。但是,在Python中我无法只提取一个文件,即使我只指定了单个文件,它也总是返回异常。

当前解决方法

我正在使用“os.popen”来使用UNIX tar二进制文件来获取README文件。

所需解决方案

使用Python tarfile包只提取单个文件。

示例错误:

UNIX(Works):

[root@athena 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
[root@athena tmp]# 
[root@athena 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

2 个答案:

答案 0 :(得分:0)

使用手动Unix方法,它看起来像gzip将文件解压缩到它断开的位置。

Python gzip(或tar)模块一旦注意到由于CRC校验失败而导致存档损坏就会退出。

只是一个想法,但您可以使用gzip预处理损坏的档案并重新压缩它们以纠正CRC。

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

这将为您提供correct.tar.gz,现在将包含所有数据,直到存档被破坏为止。您现在应该能够使用python tar / gzip库而不会出现CRC异常。

请记住,此命令将取消gzip和gzip存档,这会占用存储IO和CPU时间,并且不应对所有存档执行此操作。

为了提高效率,您应该只在遇到IOError时运行它:CRC检查失败异常。

答案 1 :(得分:0)

您可以执行以下操作 - 尝试将gzip文件解压缩为临时文件,然后尝试从中提取魔术文件。在下面的例子中,我非常热衷于尝试读取整个文件 - 取决于gzip压缩数据的块大小,最多可以读取128-256k。我的直觉告诉我,gzip最多可以工作64k块,但我没有做出任何承诺。

这个方法可以在内存中完成所有操作而无需中间文件/写入磁盘,但它确实将整个解压缩数据保存在内存中。所以我不是在开玩笑说这是为了你的具体用途 - 案件。

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