Java實時讀取日志文件


古怪的需求#

在實習的公司碰到一個古怪的需求:在一台服務器上寫日志文件,每當日志文件寫到一定大小時,比如是1G,會將這個日志文件改名成另一個名字,並新建一個與原文件名相同的日志文件,再往這個新建的日志文件里寫數據;要求寫一個程序能實時地讀取日志文件中的內容,並且不能影響寫操作與重命名操作。

RandomAccessFile類中seek方法可以從指定位置讀取文件,可以用來實現文件實時讀取。JDK文檔對RandomAccessFile的介紹

Instances of this class support both reading and writing to a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer; input operations read bytes starting at the file pointer and advance the file pointer past the bytes read. If the random access file is created in read/write mode, then output operations are also available; output operations write bytes starting at the file pointer and advance the file pointer past the bytes written. Output operations that write past the current end of the implied array cause the array to be extended.

在每一次讀取后,close一下就不會影響重命名操作了。

編碼實現#

代碼參考Java實時監控日志文件並輸出LogTailer.java

寫日志文件,每秒寫200條記錄,並且記錄寫的時間

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LogReader implements Runnable {
	private File logFile = null;
	private long lastTimeFileSize = 0; // 上次文件大小
	private static SimpleDateFormat dateFormat = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	public LogReader(File logFile) {
		this.logFile = logFile;
		lastTimeFileSize = logFile.length();
	}

	/**
	 * 實時輸出日志信息
	 */
	public void run() {
		while (true) {
			try {
				long len = logFile.length();
				if (len < lastTimeFileSize) {
					System.out.println("Log file was reset. Restarting logging from start of file.");
					lastTimeFileSize = len;
				} else if(len > lastTimeFileSize) {
					RandomAccessFile randomFile = new RandomAccessFile(logFile, "r");
					randomFile.seek(lastTimeFileSize);
					String tmp = null;
					while ((tmp = randomFile.readLine()) != null) {
						System.out.println(dateFormat.format(new Date()) + "\t"
								+ tmp);
					}
					lastTimeFileSize = randomFile.length();
					randomFile.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

實時讀取日志文件,每隔1秒讀一次

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LogReader implements Runnable {
	private File logFile = null;
	private long lastTimeFileSize = 0; // 上次文件大小
	private static SimpleDateFormat dateFormat = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	public LogReader(File logFile) {
		this.logFile = logFile;
		lastTimeFileSize = logFile.length();
	}

	/**
	 * 實時輸出日志信息
	 */
	public void run() {
		while (true) {
			try {
				RandomAccessFile randomFile = new RandomAccessFile(logFile, "r");
				randomFile.seek(lastTimeFileSize);
				String tmp = null;
				while ((tmp = randomFile.readLine()) != null) {
					System.out.println(dateFormat.format(new Date()) + "\t"
							+ tmp);
				}
				lastTimeFileSize = randomFile.length();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

開啟寫線程、讀線程,將實時信息打印在控制台。

import java.io.File;

public class RunRun {
	public static void main(String[] args) {
		File logFile = new File("mock.log");
		Thread wthread = new Thread(new LogWrite(logFile));
		wthread.start();
		Thread rthread = new Thread(new LogReader(logFile));
		rthread.start();
	}
}

在讀寫的過程中,我們可以手動將mock.log文件重命名,發現依舊可以實時讀。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM