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

Java如何检测文件新增行?定时读取日志代码异常求排查

核心问题排查

你的代码无法正常运行是几个明确的逻辑和API使用错误导致的:

  • 定时器周期配置错误:Timer.scheduleAtFixedRate的延迟、周期参数单位都是毫秒,你传入的3000对应3秒间隔,和你预期的30秒不符,需要改为30000。
  • 资源泄漏:getLineCount方法中创建的Scanner没有手动关闭,每次执行任务都会占用文件句柄,运行数次后会因文件被锁定、句柄耗尽无法读取文件,直接抛出异常。
  • 无效重复IO:单次任务里你先后两次调用getLineCount(current)和getLineCount(f),等于同一个文件全量读4次,日志文件稍大就会出现明显卡顿,也增加了文件被占用的概率。
  • 逻辑判断不可靠:仅靠对比文件行数判断新增内容存在缺陷,如果日志文件被截断、清空重写、滚动归档,会出现行数不变/下降的误判,完全识别不到内容变化;且你每次对比完成后才更新current引用,首次执行的对比基准是初始化时的旧文件状态,逻辑顺序颠倒。
优化实现方案

不要每次全量扫描文件统计行数,更合理的实现是记录上一次读取到的文件字节偏移量,每次任务启动时直接从上次结束的位置开始读取,既能直接拿到新增的日志行,也不会重复读取旧内容,性能和准确率都远高于行数统计方案。
修正后的可运行代码如下:

import java.io.File;
import java.io.RandomAccessFile;
import java.util.Timer;
import java.util.TimerTask;

public class LogMonitor {
    // 记录上次读取到的文件指针位置,初始为0即从文件头开始读
    private static long lastOffset = 0L;
    // 日志文件路径,统一配置避免重复写硬编码
    private static final File LOG_FILE = new File("C:\\Users\\/*...*/latest.log");

    public static void main(String args[]) {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                // 先判断文件是否存在,避免文件被删除/移动时抛出异常
                if (!LOG_FILE.exists() || !LOG_FILE.isFile()) {
                    System.out.println("日志文件不存在,等待下次检测");
                    return;
                }

                try (RandomAccessFile raf = new RandomAccessFile(LOG_FILE, "r")) {
                    long fileLength = raf.length();
                    // 如果当前文件长度小于上次记录的偏移量,说明文件被截断/重写,重置指针到文件头
                    if (fileLength < lastOffset) {
                        lastOffset = 0L;
                    }
                    // 移动指针到上次读取结束的位置
                    raf.seek(lastOffset);
                    String line;
                    int newLineCount = 0;
                    // 逐行读取新增内容
                    while ((line = raf.readLine()) != null) {
                        newLineCount++;
                        // 这里可以直接处理新增的日志行内容,比如打印、做规则匹配
                        System.out.println("新增日志行:" + line);
                    }
                    // 更新指针位置到当前文件末尾
                    lastOffset = raf.getFilePointer();

                    if (newLineCount > 0) {
                        System.out.println("检测到" + newLineCount + "行新增日志");
                    } else {
                        System.out.println("无新增日志");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("-------------------");
            }
        };

        Timer timer = new Timer();
        // 首次延迟3秒启动,之后每30秒执行一次
        timer.scheduleAtFixedRate(task, 3000, 30000);
        System.out.println("日志监控已启动");
    }
}
额外优化建议
  • 生产环境不建议用Timer做定时任务,Timer是单线程执行,任意一个任务抛出未捕获异常会导致整个定时器终止,推荐用ScheduledExecutorService替代,异常隔离性更好。
  • 日志读取时注意编码问题,RandomAccessFile默认按ISO-8859-1读取中文会乱码,如果日志包含中文,可以把读到的字节按对应编码(比如UTF-8)转成字符串。
  • 如果日志文件滚动生成新文件,可以增加文件inode(Linux)或文件创建时间(Windows)的判断,自动识别新的日志文件,重置读取指针。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 02:21:15