2013-11-20 43 views
12

私は7z圧縮されたcsv(テキスト)ファイルから、行単位で(Python 2.7で)読みたいと思います。私は(大きな)ファイル全体を解凍したくないのですが、行をストリームします。7zで圧縮されたテキストファイルの読み込み方法は?

私はpylzma.decompressobj()を試してみましたが、失敗しました。データエラーが発生します。このコードはまだ行ずつ読んでいないことに注意してください:

input_filename = r"testing.csv.7z" 
with open(input_filename, 'rb') as infile: 
    obj = pylzma.decompressobj() 
    o = open('decompressed.raw', 'wb') 
    obj = pylzma.decompressobj() 
    while True: 
     tmp = infile.read(1) 
     if not tmp: break 
     o.write(obj.decompress(tmp)) 
    o.close() 

出力:あなたは、Python 3.3+を使用していた場合

o.write(obj.decompress(tmp)) 
ValueError: data error during decompression 
+2

は、なぜあなたはあなたのコードとサンプルファイルを投稿しませんか? –

+0

.7zファイルは、複数のファイルを含むことができるコンテナ(アーカイブ)なので、読みたい 'testing.7z'内のファイルの名前は何ですか? – martineau

+0

@martineau、testing.csv – Yariv

答えて

7

これは、あなたが行を反復処理することができます。部分的には私がanswerで見つけたいくつかのコードから別の質問に派生しています。

私の知る限り、この時点で時間内にpy7zlibは、アーカイブメンバーがバイトストリームとして読み取ることができるようになるAPIを提供したり、文字、そのていないArchiveFileクラスだけ解凍read()機能を提供メンバーを構成するすべての非圧縮データを一度に返します。それで、あなたができる最良のことは、それをバッファとして繰り返し使用するバイトまたはラインを返すことです。以下のことがありますが、問題がアーカイブ・メンバー・ファイルそのものが巨大である場合は、多くの場合役に立ちません。

以下のコードをPython 2.7と3.xの両方で動作するように変更しました。

import io 
import os 
import py7zlib 

class SevenZFileError(py7zlib.ArchiveError): 
    pass 

class SevenZFile(object): 
    @classmethod 
    def is_7zfile(cls, filepath): 
     """ Determine if filepath points to a valid 7z archive. """ 
     is7z = False 
     fp = None 
     try: 
      fp = open(filepath, 'rb') 
      archive = py7zlib.Archive7z(fp) 
      _ = len(archive.getnames()) 
      is7z = True 
     finally: 
      if fp: fp.close() 
     return is7z 

    def __init__(self, filepath): 
     fp = open(filepath, 'rb') 
     self.filepath = filepath 
     self.archive = py7zlib.Archive7z(fp) 

    def __contains__(self, name): 
     return name in self.archive.getnames() 

    def readlines(self, name): 
     """ Iterator of lines from an archive member. """ 
     if name not in self: 
      raise SevenZFileError('archive member %r not found in %r' % 
            (name, self.filepath)) 

     for line in io.StringIO(self.archive.getmember(name).read().decode()): 
      yield line 

使用例:私たちはあなたのエラーを再現することができますし、我々は助けることができる方法を見ることができるように

import csv 

if SevenZFile.is_7zfile('testing.csv.7z'): 
    sevenZfile = SevenZFile('testing.csv.7z') 

    if 'testing.csv' not in sevenZfile: 
     print('testing.csv is not a member of testing.csv.7z') 
    else: 
     reader = csv.reader(sevenZfile.readlines('testing.csv')) 
     for row in reader: 
      print(', '.join(row)) 
2

、あなたがたlzmaモジュールを使用して、これを行うことができるかもしれませんそのバージョンの標準ライブラリに追加されました。

参照:lzmaExamples

+2

質問は 'python-2.7'とタグ付けされていますので、ここではPython 3ではないと仮定できます。 –

+0

また、python 3.3(docリンクから)と3だけでなく、言及する必要があります。 –

+1

@MartijnPietersは私がコメントしたときにそのタグを持っていませんでした。 – blakev

関連する問題