2013-02-08 38 views
2

我想從tar.gz文件中只讀取一個文件。在tar文件對象的所有操作都工作正常,但是當我從具體成員閱讀,總是StreamError升高時,檢查該代碼:從ExFileObject讀取()始終會導致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正常工作)

謝謝!

+1

有一個原因,傾倒到一個文件將無法正常工作?你可以使用'tempfile.mkdtemp'來創建一個目錄,在那裏解壓,讀取你想要的文件,然後刪除目錄。除非你無法訪問任何可寫的文件系統,或者你已經嘗試過這種方式,並且性能不可接受,否則我想不出任何其他的理由來排除它。 – abarnert

+0

'extractall'到'tmp'目錄 – jmunsch

回答

7

的問題是這一行:

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

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

如果我在一個普通的tar包上運行你的代碼,我甚至可以打印出member並且看到test/foo,然後在read上得到同樣的錯誤。

如果我修復它使用'r:gz',它的工作原理。

the docs

mode has to be a string of the form 'filemode[:compression]'

...

For special purposes, there is a second format for mode: 'filemode|[compression]'. tarfile.open() will return a TarFile object that processes its data as a stream of blocks. No random seeking will be done on the file… Use this variant in combination with e.g. sys.stdin, a socket file object or a tape device. However, such a TarFile object is limited in that it does not allow to be accessed randomly, see Examples.

'r|gz'意味着當你有一個非可查找流,它只提供了操作的子集。不幸的是,它似乎沒有準確記錄哪些操作是被允許的 - 並且與示例的鏈接沒有幫助,因爲沒有任何示例使用此功能。所以,你必須閱讀the source,或者通過反覆試驗來弄明白。

但是,既然你有一個正常的,可查找的文件,你不必擔心;只需使用'r:gz'即可。

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()) 
相關問題