代码之家  ›  专栏  ›  技术社区  ›  minou

读取格式与换行无关的非常大的文件

  •  1
  • minou  · 技术社区  · 14 年前

    我的Python代码支持以其他人创建的文件格式(称为 BLT format . BLT格式是空格和换行符独立的,因为换行符和其他空格一样被处理。此格式的主要条目是以“0”结尾的“投票”,例如。,

    1 2 3 0
    

    由于格式是独立于换行符的,所以也可以写成

    1 2
    3 0
    

    或者一行可以有多张选票:

    1 2 3 0 4 5 6 0
    

    这些文件可能非常大,所以我不想将整个文件读入内存。基于行的读取很复杂,因为数据不是基于行的。用内存高效的方式处理这些文件的好方法是什么?

    2 回复  |  直到 14 年前
        1
  •  3
  •   kindall    14 年前

    对我来说,解决这个问题最直接的方法就是使用生成器。

    def tokens(filename):
        with open(filename) as infile:
            for line in infile:
                for item in line.split():
                    yield int(item)
    
    def ballots(tokens):
        ballot = []
        for t in tokens:
            if t:
                ballot.append(t)
            else:
                yield ballot
                ballot = []
    
    t = tokens("datafile.txt")
    
    for b in ballots(t):
        print b
    

    我看到@katrielex在我发布我的解决方案时发布了一个生成器。我们之间的区别在于,我使用了两个独立的生成器,一个用于文件中的单个标记,另一个用于要解析的特定数据结构。前者作为参数传递给后者,其基本思想是可以编写如下的函数 ballots() 对于要分析的每个数据结构。您可以迭代生成器生成的所有内容,或者调用 next() 在生成器上获取下一个令牌或选票(准备 StopIteration 当您用完时出现异常,或者编写生成器以生成一个sentinel值,如 None 当他们没有真正的数据,并检查)。

    在一个类中包装整件事是非常简单的。事实上。。。

    class Parser(object):
    
        def __init__(self, filename):
    
            def tokens(filename):
                with open(filename) as infile:
                    for line in infile:
                        for item in line.split():
                            yield int(item)
    
            self.tokens = tokens(filename)
    
        def ballots(self):
            ballot = []
            for t in self.tokens:
                if t:
                    ballot.append(t)
                else:
                    yield ballot
                    ballot = []
    
    p = Parser("datafile.txt")
    
    for b in p.ballots():
        print b
    
        2
  •  1
  •   Community CDub    8 年前

    使用 generator :

    >>> def ballots(f):
    ...     ballots = []
    ...     for line in f:
    ...             for token in line.split():
    ...                     if token == '0':
    ...                             yield ballots
    ...                             ballots = []
    ...                     else:
    ...                             ballots.append(token)
    

    这将逐行读取文件,对所有空格进行拆分,并将行中的标记逐个追加到列表中。只要达到零,选票就是 yield ed和列表重置为空。