来自ExFileObject的read()总是会导致StreamError异常

时间:2013-02-08 09:34:32

标签: python extract tar

我试图从tar.gz文件中只读取一个文件。对tarfile对象的所有操作都可以正常工作,但是当我从具体成员读取时,总是引发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工作正常)

谢谢!

2 个答案:

答案 0 :(得分:7)

问题在于这一行:

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

您不希望'r|gz',您需要'r:gz'

如果我在一个简单的tarball上运行你的代码,我甚至可以打印出member并看到test/foo,然后我会在read上得到相同的错误。< / p>

如果我修复它以使用'r:gz',它就可以。

来自the docs

  

模式必须是'filemode [:compression]'

形式的字符串      

...

     

出于特殊目的,模式还有第二种格式:'filemode | [compression]'。 tarfile.open()将返回一个TarFile对象,该对象将其数据作为块流进行处理。不会对文件进行随机搜索...将此变体与例如sys.stdin,套接字文件对象或磁带设备。但是,这样的TarFile对象受到限制,因为它不允许随机访问,请参阅示例。

'r|gz'适用于具有不可搜索流的情况,并且仅提供操作的子集。不幸的是,它似乎没有准确记录允许哪些操作 - 并且到示例的链接没有帮助,因为没有一个示例使用此功能。因此,您必须阅读the source,或通过反复试验来解决问题。

但是,既然你有一个普通的,可搜索的文件,你就不用担心了;只需使用'r:gz'

答案 1 :(得分: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())