Java 利用定时实现 tail -f 功能
RandomAccessFile
可以指定位置读,指定位置写。
- getFilePointer():获取当前文件的记录指针位置
- seek(long pos):把记录指针移动 pos 处
构造方法:
RandomAccessFile raf = new RandomAccessFile(File file, String mode);
mode 取值:
" r ":可读
" w ":可写
" r w":可读可写
实现原理:
利用 RandomAccessFile 类来读取文件,在代码中记录当前文件的大小,也就是通过 getFilePointer() 获取文件读取结束的位置,下一次读取时,从这个位置开始读,保证了每次读取只读取新的内容。
存放文件读取结束的位置,需要通过一个全局变量来存放,测试时就用 static 变量实现,实际项目使用,可以在数据库中建张表存放。
实现代码:
存放全局变量的类:
public class StaticConst {
public static long filePointer = 0;
public static long getFilePointer() {
return filePointer;
}
public static void setFilePointer(long filePointer) {
StaticConst.filePointer = filePointer;
}
}
实现类:
public class BLogFileTailer extends Thread{
private File logfile; // 文件对象
// 构造函数
public BLogFileTailer(File file) { this.logfile = file; }
public void run() {
long filePointer = StaticConst.getFilePointer();
try {
RandomAccessFile file = new RandomAccessFile(logfile, "r");
long fileLength = this.logfile.length(); // 新文件的长度
// 新文件的长度小于上一次读取文件的长度时,从头开始读
if (fileLength < filePointer) {
filePointer = 0;
StaticConst.setFilePointer(filePointer);
}
// 新文件长度大于上一次读取文件的长度时
// 通过 FilePointer 从上一次读取文件的结尾开始读
if (fileLength > filePointer) {
// RandomAccessFile.seek():表示从文件的第几个位置开始搜索
file.seek(filePointer);
String line = file.readLine();
while (line != null) {
// 过滤掉:当读取到换行符 '/n' 的时候,会读取到一行的内容为空字符串
if("".equals(line)){
line = file.readLine();
continue;
}
System.out.println(line);
line = file.readLine(); // 读取下一行数据
}
// RandomAccessFile.getFilePointer():记录文件指针
filePointer = file.getFilePointer();
// 存放到全局变量中
StaticConst.setFilePointer(filePointer);
}
file.close();
} catch (IOException e) {
// 异常信息
}
}
}
测试类:
@Test
public void testTailB() {
// 测试代码时,利用 for 循环配合 Thread.sleep() 模拟定时器的效果
for (int i = 0; i < 5; i++) {
Thread t = new Thread();
try {
BLogFileTailer tailer = new BLogFileTailer(new File("e:/test.txt"));
tailer.run();
t.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}