You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取自上次运行后日志文件的新增行内容?

解决大文件新增行读取的方案

直接否定你的第一个方案:watch是持续前台监控工具,和cron定时单次执行的逻辑完全冲突,别用这个思路。

推荐用记录文件偏移量+inode的方案,这是处理这类日志增量读取的标准做法,比行号高效得多(2GB文件统计行号要遍历全量内容,太浪费资源),还能应对文件被替换/截断的情况,具体实现如下:

核心思路

  1. 每次任务运行时,先从一个记录文件里读取上次读取到的文件inode(用于判断文件是否被替换,比如日志轮转)和字节偏移量
  2. 对比当前文件的inode和大小:
    • 如果inode变了,说明文件被新文件替换,从头读取
    • 如果文件大小比上次偏移量小,说明文件被截断,也从头读取
    • 否则直接跳到上次偏移量的位置开始读取新增内容
  3. 处理完新增内容后,把当前文件的inode和最新偏移量写入记录文件,供下次使用

Python代码实现

import os

# 配置路径,根据你的实际情况修改
LOG_FILE = "/path/to/your/mylog.txt"
# 记录上次读取位置的文件,建议放在/tmp或者和日志同目录
LAST_POS_RECORD = "/tmp/last_log_position.txt"

def get_last_read_info():
    """读取上次运行时记录的文件inode和偏移量"""
    if not os.path.exists(LAST_POS_RECORD):
        return (None, 0)  # 第一次运行,无记录
    with open(LAST_POS_RECORD, 'r', encoding='utf-8') as f:
        content = f.read().strip()
        if not content:
            return (None, 0)
        try:
            inode, offset = content.split(':')
            return (int(inode), int(offset))
        except ValueError:
            # 记录文件格式错误,重置为从头读
            return (None, 0)

def update_last_read_info(current_inode, current_offset):
    """更新记录文件,写入当前的inode和偏移量"""
    with open(LAST_POS_RECORD, 'w', encoding='utf-8') as f:
        f.write(f"{current_inode}:{current_offset}")

def process_new_content():
    # 获取上次记录的信息
    last_inode, last_offset = get_last_read_info()
    # 获取当前文件的状态
    file_stat = os.stat(LOG_FILE)
    current_inode = file_stat.st_ino
    current_file_size = file_stat.st_size

    # 确定本次读取的起始偏移量
    start_offset = 0
    if last_inode == current_inode:
        # 文件未被替换,检查是否被截断
        if current_file_size >= last_offset:
            start_offset = last_offset
        else:
            print("文件已被截断,将从头读取")
    else:
        print("文件已被替换(如日志轮转),将从头读取")

    # 读取新增内容
    with open(LOG_FILE, 'r', encoding='utf-8') as f:
        f.seek(start_offset)
        # 逐行读取新增内容,避免一次性加载大内存(如果新增内容很多)
        for line in f:
            # 这里调用你已经实现的匹配和存储逻辑
            # match_and_store(line)
            pass

    # 更新记录文件,用当前文件大小作为下次的偏移量(因为文件是追加,当前大小就是下次的起始位置)
    update_last_read_info(current_inode, current_file_size)

if __name__ == "__main__":
    process_new_content()

关键说明

  • 为什么不用行号?2GB的大文件,每次统计行号需要遍历全量内容,耗时极长,而字节偏移量可以通过seek()瞬间定位,效率差几个数量级
  • 记录inode是为了处理日志轮转场景:比如原日志文件被重命名,新的同名文件创建,这时候inode会变,我们就能检测到并从头读取新文件
  • 代码里用逐行读取而不是readlines(),是为了避免新增内容过多时占用大量内存,更适合大文件场景

内容的提问来源于stack exchange,提问作者noob_coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:05:30