首页 文章

用Python逐行读取大文本文件,而不将其加载到内存中

提问于
浏览
171

我需要逐行读取一个大文件 . 假设文件超过5GB,我需要读取每一行,但显然我不想使用 readlines() ,因为它会在内存中创建一个非常大的列表 .

以下代码如何适用于此案例? xreadlines 本身是一个一个地读入内存吗?是否需要生成器表达式?

f = (line for line in open("log.txt").xreadlines())  # how much is loaded in memory?

f.next()

另外,我可以做什么来以相反的顺序阅读它,就像Linux tail 命令一样?

我发现:

http://code.google.com/p/pytailer/

python head, tail and backward read by lines of a text file

两者都运作得很好!

13 回答

  • -1

    请试试这个:

    with open('filename','r',buffering=100000) as f:
        for line in f:
            print line
    
  • 3

    您需要做的就是使用文件对象作为迭代器 .

    for line in open("log.txt"):
        do_something_with(line)
    

    更好的是在最近的Python版本中使用上下文管理器 .

    with open("log.txt") as fileobject:
        for line in fileobject:
            do_something_with(line)
    

    这也会自动关闭文件 .

  • 234

    这个怎么样?将文件分成块然后逐行读取,因为当您读取文件时,操作系统将缓存下一行 . 如果您逐行读取文件,则无法有效使用缓存的信息 .

    相反,将文件分成块并将整个块加载到内存中然后进行处理 .

    def chunks(file,size=1024):
        while 1:
    
            startat=fh.tell()
            print startat #file's object current position from the start
            fh.seek(size,1) #offset from current postion -->1
            data=fh.readline()
            yield startat,fh.tell()-startat #doesnt store whole list in memory
            if not data:
                break
    if os.path.isfile(fname):
        try:
            fh=open(fname,'rb') 
        except IOError as e: #file --> permission denied
            print "I/O error({0}): {1}".format(e.errno, e.strerror)
        except Exception as e1: #handle other exceptions such as attribute errors
            print "Unexpected error: {0}".format(e1)
        for ele in chunks(fh):
            fh.seek(ele[0])#startat
            data=fh.read(ele[1])#endat
            print data
    
  • 3

    下面是加载任何大小的文本文件而不会导致内存问题的代码 . It support gigabytes sized files

    https://gist.github.com/iyvinjose/e6c1cb2821abd5f01fd1b9065cbc759d

    下载文件 data_loading_utils.py 并将其导入您的代码

    用法

    import data_loading_utils.py.py
    file_name = 'file_name.ext'
    CHUNK_SIZE = 1000000
    
    
    def process_lines(data, eof, file_name):
    
        # check if end of file reached
        if not eof:
             # process data, data is one single line of the file
    
        else:
             # end of file reached
    
    data_loading_utils.read_lines_from_file_as_data_chunks(file_name, chunk_size=CHUNK_SIZE, callback=self.process_lines)
    

    process_lines 方法是回调函数 . 它将被调用所有行,参数数据一次代表文件的一行 .

    您可以根据计算机硬件配置配置变量 CHUNK_SIZE .

  • 11
    f=open('filename','r').read()
    f1=f.split('\n')
    for i in range (len(f1)):
        do_something_with(f1[i])
    

    希望这可以帮助 .

  • 0

    如果您在文件中没有换行符,请执行以下操作:

    with open('large_text.txt') as f:
      while True:
        c = f.read(1024)
        if not c:
          break
        print(c)
    
  • 14

    你最好使用迭代器 . 相关:http://docs.python.org/library/fileinput.html

    来自文档:

    import fileinput
    for line in fileinput.input("filename"):
        process(line)
    

    这样可以避免一次将整个文件复制到内存中 .

  • -9

    我在另一个问题中演示了并行字节级随机访问方法:

    Getting number of lines in a text file without readlines

    已经提供的一些答案很简洁 . 我喜欢其中的一些 . 但这实际上取决于你想要对文件中的数据做什么 . 在我的情况下,我只想在大文本文件上尽可能快地计算行数 . 我的代码当然可以修改为做其他事情,就像任何代码一样 .

  • 0

    我似乎无法回答这个问题 . 所以,我使用逐行读写来重新创建 cp 命令 . 这很疯狂 .

    #!/usr/bin/env python3.6
    
    import sys
    
    with open(sys.argv[2], 'w') as outfile:
        with open(sys.argv[1]) as infile:
            for line in infile:
                outfile.write(line)
    
  • 43

    在过去的6年里,blaze项目取得了长足的进步 . 它有一个简单的API,涵盖了一个有用的pandas功能子集 .

    dask.dataframe在内部负责分块,支持许多可并行操作,并允许您将切片轻松导出回到pandas以进行内存操作 .

    import dask.dataframe as dd
    
    df = dd.read_csv('filename.csv')
    df.head(10)  # return first 10 rows
    df.tail(10)  # return last 10 rows
    
    # iterate rows
    for idx, row in df.iterrows():
        ...
    
    # group by my_field and return mean
    df.groupby(df.my_field).value.mean().compute()
    
    # slice by column
    df[df.my_field=='XYZ'].compute()
    
  • 0

    我提供了这个答案,因为Keith 's, while succinct, doesn't明确地关闭了文件

    with open("log.txt") as infile:
        for line in infile:
            do_something_with(line)
    
  • 0

    旧学校方法:

    fh = open(file_name, 'rt')
    line = fh.readline()
    while line:
        # do stuff with line
        line = fh.readline()
    fh.close()
    
  • 0

    谢谢!我最近转换为python 3并且因使用readlines(0)读取大文件而感到沮丧 . 这解决了这个问题 . 但要获得每一条线,我不得不做几个额外的步骤 . 每行前面都有一个“b”,我猜它是二进制格式 . 使用“decode(utf-8)”将其更改为ascii .

    然后我不得不在每行的中间删除一个“= \ n” .

    然后我在新线上分割线条 .

    b_data=(fh.read(ele[1]))#endat This is one chunk of ascii data in binary format
            a_data=((binascii.b2a_qp(b_data)).decode('utf-8')) #Data chunk in 'split' ascii format
            data_chunk = (a_data.replace('=\n','').strip()) #Splitting characters removed
            data_list = data_chunk.split('\n')  #List containing lines in chunk
            #print(data_list,'\n')
            #time.sleep(1)
            for j in range(len(data_list)): #iterate through data_list to get each item 
                i += 1
                line_of_data = data_list[j]
                print(line_of_data)
    

    以下是Arohi代码中“打印数据”上方的代码 .

相关问题