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();
}
}
}