惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
IT之家
IT之家
T
The Blog of Author Tim Ferriss
V
V2EX
博客园 - 聂微东
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
U
Unit 42
Vercel News
Vercel News
L
LangChain Blog
博客园 - 司徒正美
H
Help Net Security
Recent Announcements
Recent Announcements
Recorded Future
Recorded Future
V
Visual Studio Blog
Jina AI
Jina AI
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
Y
Y Combinator Blog
C
Check Point Blog
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
J
Java Code Geeks
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
F
Fortinet All Blogs
B
Blog
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
MongoDB | Blog
MongoDB | Blog
F
Full Disclosure
有赞技术团队
有赞技术团队
罗磊的独立博客
博客园_首页
MyScale Blog
MyScale Blog
aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence
N
Netflix TechBlog - Medium
Engineering at Meta
Engineering at Meta
量子位
I
InfoQ
小众软件
小众软件
P
Proofpoint News Feed

博客园 - _herbert

小程序拍证件并局部裁剪 信创-为什么ORACLE使用JDBC查询SYSDATE时,RS.getDate能获取到时间部分? linux宝塔面板使用API自动部署更新文件 JSON JAVA找出哪个类import了不存在的类 LocalDate,LocalDateTime,Date,日期串相互转换 PostMan加载三方JS PostMan内置对象 微信支付集成_JSAPI VUE中使用AXIOS包装API代理 spring中el表达式安全和扩展 Spring使用el表达式 springboot中File默认路径 Springboot启动时记录进程ID ORACLE解析游标生成JSON ORACLE游标序列化 AI教我一条SQL实现明细转树形结构 Springboot构建包使用BOOT-INF中的class覆盖依赖包中的class Maven 构建知识库 MAVEN构建分离依赖JAR 信创-ORACLE迁移到KingbaseV9 信创-ORACLE迁移到DM8 sql分组 group by rollup,cube,grouping sets,group_id,groupingId
JAVA实现读取最后几行日志
_herbert · 2025-06-02 · via 博客园 - _herbert

JAVA实现读取最后几行日志

1. 背景

在项目框架设计中,针对系统产生的日志,有线上查看日志的需求.日志文件本身很大.线上查看时,开发人员只想了解当前系统产生的错误信息.

2. POM依赖

主要使用 ReversedLinesFileReader 实现到读日志文件,需要引入commons-io依赖,底层使用 RandomAccessFile 实现.

 <dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.6</version>
 </dependency>

3. 代码实现

先倒序读取每行数据,放入集合中.然后集合倒序,返回符合阅读习惯的文本日志.

public String readLastLines(String filePath, int lines) throws IOException {
  if(StringUtils.isBlank(filePath)|| lines<=0){
    return "";
  }
  List<String> lastLine = new ArrayList<String>();
  ReversedLinesFileReader reader = null;
  try {
    reader = new ReversedLinesFileReader(filePath, StandardCharsets.UTF_8);
    String line = "";
    while ((line = reader.readLine()) != null && lastLine.size() < lines) {
      lastLine.add(line);
    }
    Collections.reverse(lastLine);
  } catch (IOException e) {
    System.out.println("读取文件失败,公众号:小满小慢,小游戏:地心侠士");
  } finally {
    if (reader != null) {
      try {
        reader.close();
      } catch (IOException e) {
        System.out.println("关闭文件失败,,公众号:小满小慢,小游戏:地心侠士");
      }
    }
  }
  return StringUtils.join(lastLine, "\r\n");
}

4. RandomAccessFile 基本使用

使用 RandomAccessFile类,实现倒序读取内容

@Test
   public void testReadLogFile() {
   	File logFile = new File("./logs/spring.log");
   	RandomAccessFile reader = null;
   	try {
   		reader = new RandomAccessFile(logFile, "r");
   		System.out.println(reader.readUTF());
   		reader.seek(logFile.length() - 1);
   		byte c = -1;
   		List<Byte> l = new ArrayList<Byte>();
   		do {
   			c = reader.readByte();
   			if (c == '\r' || c == '\n') {
   				byte[] bytes = new byte[l.size()];
   				for (int i = 0; i < l.size(); i++) {
   					bytes[i] = l.get(i);
   				}
   				String line = new String(bytes, StandardCharsets.UTF_8);
   				System.out.println("地心侠士:"+ line);
   				l = new ArrayList<Byte>();
   			}
   		} while (reader.getFilePointer() != logFile.length());
   		System.out.println("地心侠士:" +logFile.length());
   	} catch (IOException e) {
   		e.printStackTrace();
   	} finally {
   		if (reader != null) {
   			try {
   				reader.close();
   			} catch (IOException e) {

   			}
   		}
   	}
   }