2013-11-20 7 views
12

필자는 7z 압축 된 csv (text) 파일에서 한 행씩 (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() 

출력 : 파이썬 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() 기능을 제공합니다 멤버로 구성된 모든 압축되지 않은 데이터를 즉시 반환합니다. 그것을 감안할 때 최선의 방법은 바이트 또는 라인을 반복적으로 버퍼로 사용하는 것입니다. 다음은 그렇게하지만 많은 경우 문제가 아카이브 멤버 파일 자체가 큰 경우 도움이되지 않습니다.

파이썬 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' 태그가 붙어 있으므로 파이썬 3이 아닌 것으로 가정 할 수 있습니다. –

+0

또한 파이썬 3.3 (doc 링크에서)과 3을 언급해야합니다. –

+1

@MartijnPieters는 내가 주석을 달았을 때 그 태그를 가지고 있지 않았습니다. – blakev

관련 문제