VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > python入门教程 >
  • Python3 反向按行读取大文件、日志read_reverse_bigfile

适用场景:

  反向读取大文件的需求,多半出于想要获取超大的日志文件最后几百行内容,小文件直接通过 lins = file.readlines()[-200:] 就可以直接得出了,

大文件readlines() 会将文件内容全部读取到内存,在GB大小情况下,内存不一定够,列表切片性能差。 生成器反向读取方式更合适。

反向读取大文件,主要依据:
  • file对象的seek()函数,偏移文件指针
  • re 模块finditer 搜寻文件行尾符,Match对象的end获取行尾符索引位置
  • yield 生成器 节省内存 

 性能验证: 

在windows10, RAM 16G,处理器 11th Gen Intel(R) Core(TM) i5-11400 @ 2.60GHz   2.59 GHz , python 3.7.11 下简单验证,

  1. 读取220M,722万行 文本文件,按行转为列表,read_reverse_bigfile 耗时大概3.8s,内存774MB, file对象readlines()函数,正序读取同样文件耗时大概1.1s,内存552MB。
  2. 取最后200行内容,read_reverse_bigfile 结果转列表,耗时大概0.8s,占用内存约12MB,file对象readlines()函数 ,列表切片,1.1s,内存约552MB。

 

 

复制代码
import re


def read_reverse_bigfile(filepath, encoding='utf-8', separator=b'\n', single_size=1024 * 1024):
    """
    :param filepath: 文件路径
    :param encoding: 字符编码,默认utf-8
    :param separator: 行尾分隔符,默认 '\n'
    :param single_size: 单次读取 字符量,默认 1024*1024
    :return: generator 
    """
    with open(filepath, 'rb') as f:
        try:
            f.seek(0, 2)
            position = f.tell()
            if position > single_size:
                f.seek(-single_size, 2)
            else:
                f.seek(0, 0)
        except OSError as e:
            return 'Blank file'
        line = b''
        while 1:
            chunk = f.read(single_size)
            index_list = [match.end() for match in re.finditer(separator, chunk)]
            index = None
            while index_list:
                target = index_list.pop()
                if index is None:
                    line = chunk[target:] + line
                else:
                    line = chunk[target:index] + line
                if line:
                    yield line.decode(encoding=encoding)
                line = b''
                index = target
            else:
                line = chunk[:index] + line
            position = f.tell()
            if position > 2 * single_size and single_size > 0:
                f.seek(-2 * single_size, 1)
            else:
                f.seek(0, 0)
                single_size = position - single_size
                if single_size <= 0:
                    yield line.decode(encoding=encoding)
                    return 'End'

if __name__ == '__main__':
    import time
    import os
    import psutil
    pid = os.getpid()
    p = psutil.Process(pid)
    start_time = time.time()
    fp = r'./test30.txt'
    rrb = list(read_reverse_bigfile(fp))
    print(len(rrb))
    print(f'耗时0:{time.time() - start_time}')
    with open(fp, encoding='utf-8') as f:
        orl = f.readlines()
        print(len(orl))
    print(f'耗时1:{time.time() - start_time}')

    info = p.memory_full_info().uss/(1024*1024)
    print(f'内存信息:{info}MB')
 
复制代码
出处:https://www.cnblogs.com/yougnen/p/16081877.html

相关教程