这是我关于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
答案 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