从ExFileObject读取时总是引发StreamError异常
我想从一个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方法工作得很好)。
谢谢!
2 个回答
除了文件模式之外,我还尝试在网络流上使用 seek
。
当我试图用 requests.get
获取文件时也遇到了同样的错误,所以我把所有东西提取到了一个临时目录:
# 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())
问题出在这一行:
fd = tarfile.open('file.tar.gz', 'r|gz')
你不应该用 'r|gz'
,而应该用 'r:gz'
。
如果我在一个简单的压缩包上运行你的代码,我甚至可以打印出 member
,看到 test/foo
,然后我在 read
时也会遇到和你一样的错误。
如果我把它改成 'r:gz'
,就能正常工作了。
根据文档:
模式必须是 'filemode[:compression]' 这种格式的字符串。
...
为了特殊目的,模式还有第二种格式:'filemode|[compression]'。tarfile.open() 会返回一个 TarFile 对象,它将数据作为块流处理。这个文件不会进行随机访问……在与例如 sys.stdin、套接字文件对象或磁带设备结合使用时,使用这种变体。然而,这种 TarFile 对象的限制在于它不允许随机访问,具体可以参考示例。
'r|gz'
是为那些没有随机访问的流设计的,它只提供了一部分操作。遗憾的是,文档中似乎没有明确说明哪些操作是允许的——而且示例链接也没有帮助,因为没有一个示例使用这个功能。所以,你要么去看源代码,要么通过反复尝试来搞明白。
但是,因为你有一个正常的、可以随机访问的文件,所以你不需要担心这些;只需使用 'r:gz'
就可以了。