如何获取自上次运行后日志文件的新增行内容?
解决大文件新增行读取的方案
直接否定你的第一个方案:watch是持续前台监控工具,和cron定时单次执行的逻辑完全冲突,别用这个思路。
推荐用记录文件偏移量+inode的方案,这是处理这类日志增量读取的标准做法,比行号高效得多(2GB文件统计行号要遍历全量内容,太浪费资源),还能应对文件被替换/截断的情况,具体实现如下:
核心思路
- 每次任务运行时,先从一个记录文件里读取上次读取到的文件inode(用于判断文件是否被替换,比如日志轮转)和字节偏移量
- 对比当前文件的inode和大小:
- 如果inode变了,说明文件被新文件替换,从头读取
- 如果文件大小比上次偏移量小,说明文件被截断,也从头读取
- 否则直接跳到上次偏移量的位置开始读取新增内容
- 处理完新增内容后,把当前文件的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
相关产品推荐
相关产品推荐

