在Python中使用csvreader读取gzip压缩文件

33

我有许多经过gzip压缩的CSV文件,我想使用Python内置的CSV读取器打开并检查它们。我想在不必手动将它们解压到磁盘上的情况下完成此操作。我猜我想要以某种方式获取未压缩数据的流,并将其传递给CSV读取器。在Python中是否有可能实现这一点?


除了本地的Python解决方案之外,pandas包还提供了具有gzip支持的read_csv读取器。 - smci
只需补充一点,在pandas中,可以通过将compression="gzip"作为参数添加到read_csv中来完成此操作。 - Rik Mulder
3个回答

44

使用gzip模块:

with gzip.open(filename, mode='rt') as f:
    reader = csv.reader(f)
    #...

1
它不会创建档案。Gzip 只是一个流压缩器。文件名应该被称为“tzsman.csv.gz”以帮助识别文件类型。此外,gzip 库不支持 Python 2.6.8 中的 with 语句。 - Doug
@Doug:你可以使用contextlib将非上下文管理器对象装饰起来,并添加虚拟的__enter__/__exit__()方法,但最好还是实现真正的上下文管理器。 - smci
1
@smci 感谢你的提示。快进3年半,我现在完全使用Python 3.6,除非我需要访问像yum这样的旧API。contextlib确实提供了一些漂亮的装饰器。 - Doug
1
@mazs,你可以在gzip.open调用中指定文件模式。 - tzaman
@Devy 如上所述,您可以在 open 调用中指定模式。我已经编辑了答案以在文本模式下打开,这应该可以解决错误。 - tzaman
显示剩余4条评论

29

我已经尝试了上述版本进行编写和阅读,但在Python 3.3中由于“bytes”错误而无法使用。然而,在一些尝试和错误之后,我能够使以下内容正常工作。也许这对其他人有所帮助:

import csv
import gzip
import io


with gzip.open("test.gz", "w") as file:
    writer = csv.writer(io.TextIOWrapper(file, newline="", write_through=True))
    writer.writerow([1, 2, 3])
    writer.writerow([4, 5, 6])

with gzip.open("test.gz", "r") as file:
    reader = csv.reader(io.TextIOWrapper(file, newline=""))
    print(list(reader))

如amohr所建议的那样,以下方法同样有效:

import gzip, csv

with gzip.open("test.gz", "wt", newline="") as file:
    writer = csv.writer(file)
    writer.writerow([1, 2, 3])
    writer.writerow([4, 5, 6])

with gzip.open("test.gz", "rt", newline="") as file:
    reader = csv.reader(file)
    print(list(reader))

这个解决方案也适用于 io.BufferedReader,根据一些基准测试可能会更快。只需使用 io.BufferedReader 包装 gzip.open,使其变为 with io.BufferedReader(gzip.open("test.gz", 'r')) as file: - Niklas B
4
如果使用 gzip.open(mode ='rt'),则可以跳过 TextIOWrapper / BufferedReader。 - amohr
这很有用。但我遇到了一个问题。我手头有一个被压缩的TSV文件,也就是制表符分隔的文件,而不是逗号分隔的文件。如何将制表符转换为逗号? - Alhpa Delta
你可能会用到 csv.reader,它有很多选项可以自定义格式 https://docs.python.org/3.6/library/csv.html#csv-fmt-params - Gere

7
一个更完整的解决方案:
import csv, gzip
class GZipCSVReader:
    def __init__(self, filename):
        self.gzfile = gzip.open(filename)
        self.reader = csv.DictReader(self.gzfile)
    def next(self):
        return self.reader.next()
    def close(self):
        self.gzfile.close()
    def __iter__(self):
        return self.reader.__iter__()

现在您可以像这样使用它:
r = GZipCSVReader('my.csv')
for map in r:
    for k,v in map:
        print k,v
r.close()

编辑:根据下面的评论,采用更简单的方法:

def gzipped_csv(filename):
    with gzip.open(filename) as f:
        r = csv.DictReader(f)
        for row in r:
            yield row

这使您随后可以

for row in gzipped_csv(filename):
    for k, v in row:
        print(k, v)

整洁。如果您可以添加__enter__/__exit__()上下文管理器方法,那就更整洁了,这样它就可以与with语句一起使用。 - smci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接