【问题标题】:Read CSV file in chunks using generator使用生成器分块读取 CSV 文件
【发布时间】:2019-04-13 14:22:41
【问题描述】:

我有一个需要处理的大 csv 文件,它是通过这种方式完成的(非常简单):

import csv
from csv import excel

def _get_dialect():
    class CustomDialect(excel):
        delimiter = ','
    return CustomDialect()

class DictIter:
    def __init__(self):
        self.reader = csv.DictReader(open('test.csv'), 
                                     fieldnames=['col1', 'col2'], 
                                     dialect=_get_dialect())

    def __iter__(self):
        return self

    def __next__(self):
        return self.reader.__next__()

items = DictIter()
for item in items:
    print(item)

有更好的方法来做到这一点,但这就是我现在所拥有的。 现在我想将处理拆分成块,并找到了适合我的简单解决方案:

def gen_chunks(reader, chunksize=500):
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]
        chunk.append(line)
    yield chunk

但是我缺乏一些生成器知识来将这两段代码组合在一起。基本上我想要这样的东西:

import csv
from csv import excel

def gen_chunks(reader, chunksize=500):
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]
        chunk.append(line)
    yield chunk

def _get_dialect():
    class CustomDialect(excel):
        delimiter = ','
    return CustomDialect()

class DictIter:
    def __init__(self):
        self.reader = csv.DictReader(open('test.csv'), 
                                     fieldnames=['col1', 'col2'], 
                                     dialect=_get_dialect())

    def __iter__(self):
        return self

    def __next__(self):
        for chunk in gen_chunks(self.reader):
            for item in chunk:
                yield item

items = DictIter()
for item in items:
    print(item)

这可能有点笨拙,但我想在对当前结构进行最小更改的情况下实现拆分处理。我想要实现的是将当前实现保留为迭代器类,但一次处理一个块,并在完成前一个块时产生下一个块。

【问题讨论】:

    标签: python python-3.x csv iterator generator


    【解决方案1】:

    您的解决方案看起来过于复杂:

    import csv
    
    with open('test.csv',newline='') as f:
        reader = csv.DictReader(f,fieldnames=['col1', 'col2'])
        for item in reader:
            print(item)
    

    您的分块仍然一次返回一个项目。 excel 方言的默认分隔符是逗号,excel 是默认方言。

    注意newline='' 是文档化的打开文件的方法,传递给csv 读取器或写入器对象。

    如果您有真正的分块原因(多处理?),您应该说明这一点,如果它不起作用,则显示 尝试。

    【讨论】:

    • 我当前的代码过于复杂,因为该类有很多其他的东西,为了简化,这里没有显示,应该作为一个迭代器类。我分块的原因是一些 csv 文件非常大,服务器的 RAM 有限,所以我想分块处理文件。读取文件后,会发生大量消耗资源的数据过滤和转换。我想要实现的是将当前实现保留为迭代器类,但一次处理一个块,并在完成前一个块时产生下一个块。
    • @NST 读取 500 行并将它们作为列表一次处理与一次处理它们有什么区别?它使用 more ram 读取 500 行而不是一次...操作系统正在缓存文件读取给你。这看起来像是过早“优化”的情况。确保测量...
    • @MarkTolonen 我不认为你的回答涵盖了大块部分!特别是在最后一行你质疑问题的目的!我觉得这不是问题的答案。
    • @user702846 不需要。分块对于单个进程毫无意义。 OP 使问题过于复杂。
    猜你喜欢
    • 1970-01-01
    • 2017-09-26
    • 2016-11-29
    • 2015-12-20
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-05-05
    • 1970-01-01
    相关资源
    最近更新 更多