2013-11-20 68 views
12

我想从csv(文本)文件中读取(在Python 2.7中),它是7z压缩的。我不想对整个(大)文件进行解压缩,而是对这些行进行流式处理。如何从使用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() 

输出:

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

你为什么不发布您的代码和一个示例文件,这样我们就可以复制你的错误,可以看到我们可以如何帮助? –

+0

.7z文件是可以包含多个文件的容器(档案文件),那么您想要读取的'tests.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

如果你使用Python 3.3+,您可能能够做到这一点使用lzma模块这是添加到该版本的标准库中。

请参见:lzmaExamples

+2

这个问题用'python-2.7'标记,所以我们可以假设它不是* Python * 3。 –

+0

另外,你应该提到python 3.3(来自doc链接),而不仅仅是3 –

+1

@MartijnPieters在我评论时没有这个标签。 – blakev

相关问题