使用 python 生成器处理大型文本文件

using a python generator to process large text files

我刚开始使用生成器并阅读了一些内容,但需要一些帮助来处理成块的大文本文件。我知道这个话题已经被涵盖了,但是示例代码的解释非常有限,如果不明白发生了什么,就很难修改代码。

我的问题相当简单,我有一系列包含以下格式的人类基因组测序数据的大型文本文件:

chr22   1   0
chr22   2   0
chr22   3   1
chr22   4   1
chr22   5   1
chr22   6   2

文件长度在 1Gb 到 ~20Gb 之间,太大而无法读入 RAM。所以我想一次读取 chunks/bins 中的行,比如 10000 行,这样我就可以在这些 bin 大小的最后一列上执行计算。

基于此link here我写了以下内容:

def read_large_file(file_object):
    """A generator function to read a large file lazily."""

    bin_size=5000
    start=0
    end=start+bin_size

    # Read a block from the file: data
    while True:
        data = file_object.readlines(end) 
        if not data:
            break
        start=start+bin_size
        end=end+bin_size
        yield data


def process_file(path):

    try:
        # Open a connection to the file
        with open(path) as file_handler:
            # Create a generator object for the file: gen_file
            for block in read_large_file(file_handler):
                print(block)
                # process block

    except (IOError, OSError):
        print("Error opening / processing file")    
    return    

if __name__ == '__main__':
            path='C:/path_to/input.txt'
    process_file(path)

在 'process_block' 内 我期望返回的 'block' 对象是一个 10000 个元素长的列表,但它不是?第一个列表是 843 个元素。第二个是2394个元素?

我想返回块中的 'N' 行数,但对这里发生的事情感到很困惑?

这个解决方案 here 似乎可以提供帮助,但我还是不明白如何修改它以一次读取 N 行?

这个 here 看起来也是一个非常好的解决方案,但同样,没有足够的背景解释让我无法理解足以修改代码。

任何帮助将不胜感激?

与其使用文件中的偏移量,不如尝试从循环中构建并生成包含 10000 个元素的列表:

def read_large_file(file_handler, block_size=10000):
    block = []
    for line in file_handler:
        block.append(line)
        if len(block) == block_size:
            yield block
            block = []

    # don't forget to yield the last block
    if block:
        yield block

with open(path) as file_handler:
    for block in read_large_file(file_handler):
        print(block)

如果它能帮助其他遇到类似问题的人,这里是一个基于 here

的解决方案
import pandas as pd

def process_file(path,binSize):

    for chunk in pd.read_csv(path, sep='\t', chunksize=binSize):
        print(chunk)
        print(chunk.ix[:,2]) # get 3rd col
        # Do something with chunk....  

if __name__ == '__main__':
    path='path_to/infile.txt'
    binSize=5000
    process_file(path,binSize)

不是正确答案,但找出此行为的原因大约需要 27 秒:

(blook)bruno@bigb:~/Work/blookup/src/project$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
pythonrc start
pythonrc done
>>> help(file.readlines)

Help on method_descriptor:

readlines(...)
    readlines([size]) -> list of strings, each a line from the file.

    Call readline() repeatedly and return a list of the lines so read.
    The optional size argument, if given, is an approximate bound on the
    total number of bytes in the lines returned.

我明白并不是这里的每个人都是专业程序员 - 当然 文档并不总是足以解决问题(我很乐意回答这类问题) , 但实际上在文档开头用普通字母写答案的问题数量确实有点烦人。