【问题标题】:read() from a ExFileObject always cause StreamError exception从 ExFileObject 读取()总是导致 StreamError 异常
【发布时间】:2013-02-08 09:34:31
【问题描述】:

我试图从 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: 不允许向后搜索”

我需要将内容读取到内存中,而不是转储到文件中(extractall 工作正常)

谢谢!

【问题讨论】:

  • 是否存在无法转储到文件的原因?您可以使用,例如,tempfile.mkdtemp 创建一个目录,在那里解压,读取您想要的文件,然后删除该目录。除非您可能无法访问任何可写文件系统,或者您已经尝试过并且性能无法接受,否则我想不出任何其他理由来排除它。
  • extractalltmp 目录

标签: python extract tar


【解决方案1】:

问题出在这一行:

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

你不想要'r|gz',你想要'r:gz'

如果我在一个简单的 tarball 上运行您的代码,我什至可以打印出 member 并查看 test/foo,然后我在 read 上遇到与您相同的错误。

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

来自the docs

mode 必须是 'filemode[:compression]' 形式的字符串

...

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

'r|gz' 适用于当您有不可搜索的流时,它只提供操作的子集。不幸的是,它似乎没有准确记录哪些操作是允许的——并且示例的链接也无济于事,因为没有一个示例使用此功能。所以,你要么阅读the source,要么通过反复试验弄清楚。

但是,由于您有一个普通的、可搜索的文件,您不必担心这一点;只需使用'r:gz'

【讨论】:

    【解决方案2】:

    除了文件模式外,我还尝试在网络流上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())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多