Python一行代码实现Linux的tail

问题描述

实现Linux的tail,输出文件最后n行

在这里插入图片描述




解决方案

利用collections.deque




代码

不断往test.txt写入数据

i = 0
while True:
    with open('test.txt', 'a') as f:
        print(f.write(f'{i}\n'))
    i += 1

间断读取

import time
from collections import deque

while True:
    print(''.join(deque(open('test.txt'), 10)))
    print()
    time.sleep(2)

命令行,第一个参数为文件名,第二个参数为返回行数

python -c "import sys; from collections import deque; print(''.join(deque(open(sys.argv[1]), int(sys.argv[2]) if sys.argv[2] else 10)))" test.txt 5

在这里插入图片描述

缺点:不适合大文件




超大文件处理

使用超过1GB的文件,使用上述方法需要10s,以下方法几乎不耗时

不断写日志

import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
fileHandler = logging.FileHandler('test.log', mode='a')
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
fileHandler.setFormatter(formatter)
logger.addHandler(fileHandler)

i = 0
while True:
    logger.info(str(i))
    i += 1

超大文件tail,从后往前读
在这里插入图片描述

import time


def tail(f, size=10):
    '''类似Linux的tail命令'''
    if size == 0:
        return []

    BUFSIZE = 1024  # 一次读取长度
    f.seek(0, 2)  # 将流位置改为末尾
    remaining_bytes = f.tell()  # 当前流的位置
    block = -1
    data = []

    while size >= 0 and remaining_bytes > 0:
        if remaining_bytes - BUFSIZE > 0:
            f.seek(block * BUFSIZE, 2)  # 将流位置改为给定的偏移位置
            bunch = f.read(BUFSIZE)  # 读取
        else:
            f.seek(0, 0)  # 文件太小,从头开始
            bunch = f.read(remaining_bytes)  # 只读没读过的东西

        bunch = bunch.decode('utf-8')
        data.insert(0, bunch)
        size -= bunch.count('\n')  # 读够一行减一次
        remaining_bytes -= BUFSIZE
        block -= 1  # 继续往回读

    return ''.join(data).splitlines()[-size:]


beg = time.time()
print(tail(f=open('test.log', 'rb')))
print(time.time() - beg)

推荐阅读:

  1. io — 处理流的核心工具




流式读取

该方法为顺序流式读取

from functools import partial


def read_from_file(filename, block_size=1024 * 8):
    with open(filename, "r") as fp:
        for chunk in iter(partial(fp.read, block_size), ""):
            yield chunk


for i in range(10):
    print(next(read_from_file('test.log')))




参考文献

  1. tail命令
  2. deque 用法
  3. 如何流式读取数G超大文件
  4. logPatrol GitHub
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值