@Author Jacky Wang
碰到一个需求,在某个服务的日志文件达到指定大小之后,删除该日志文件前面多少行,在后面追加新的日志。以下,为此次使用随机文件流操作文件内容所记。
/**
* @Title: removeFileLine
* @Description: TODO(该方法为从文件开头删除前n行)
* @param: @param file 文件
* @param: @param lineNum 删除的行行数
* @param: @throws IOException
* @return: void
* @throws
*/
public void removeFileLine(File file, int lineNum) throws IOException {
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(file, "rw");
// Initial write position.
// 写文件的位置标记,从文件开头开始,后续读取文件内容从该标记开始
long writePosition = raf.getFilePointer();
for (int i = 0; i < lineNum; i++) {
String line = raf.readLine();
if (line == null) {
break;
}
}
// Shift the next lines upwards.
// 读文件的位置标记,写完之后回到该标记继续读该行
long readPosition = raf.getFilePointer();
// 利用两个标记,
byte[] buff = new byte[1024];
int n;
while (-1 != (n = raf.read(buff))) {
raf.seek(writePosition);
raf.write(buff, 0, n);
readPosition += n;
writePosition += n;
raf.seek(readPosition);
}
raf.setLength(writePosition);
} catch (IOException e) {
logger.error("readAndRemoveFirstLines error", e);
throw e;
} finally {
try {
if (raf != null) {
raf.close();
}
} catch (IOException e) {
logger.error("close RandomAccessFile error", e);
throw e;
}
}
}
/**
* @Title: appendContentToFile
* @Description: TODO(在文件末尾追加内容)
* @param: @param file
* @param: @param content
* @param: @throws IOException
* @return: void
* @throws
*/
public static void appendContentToFile(File file, String content) throws IOException {
RandomAccessFile randomFile = null;
try {
// 打开一个随机访问文件流,按读写方式
randomFile = new RandomAccessFile(file, "rw");
// 文件长度,字节数
long fileLength = randomFile.length();
// 将写文件指针移到文件尾。
randomFile.seek(fileLength);
randomFile.writeBytes(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (randomFile != null) {
randomFile.close();
randomFile = null;
}
}
}
/**
* @Title: checkFileInSize
* @Description: TODO(检查文件字节数是否超出限制)
* @param: @param file
* @param: @param limitSize
* @param: @return
* @return: boolean
* @throws
*/
private boolean checkFileInSize(File file, Long limitSize) {
return file.length() <= limitSize;
}
以上就是上述需求用到的方法了,下面将上面的方法整合完成需求。
@Component
@SuppressWarnings("restriction")
@PropertySource("classpath:/config/ivg.properties")
public class AppStartupListener implements ApplicationRunner {
@Value("${log.startup.path}")
private String logPath;// 日志保存路径
@Value("${log.startup.output.statement}")
private String outputStatement;// 追加日志内容模板
@Value("${log.startup.limit.size}")
private Long limitSize;// 文件大小限制,eg:50M:50*1024*1024 = 52428800
@Value("${log.startup.remove.line}")
private int removeLineNum;// 超过限制之后一次删除多少行
private void initLog() {
logger.info("***程序启动日志记录开始***");
// 检查文件是否存在
File file = null;
try {
file = new File(logPath);
if (!file.exists() || !file.isFile()) {
logger.info("file is not exist,creating " + logPath + " now...");
file.createNewFile();
}
StringBuilder sb = new StringBuilder(outputStatement);
SimpleDateFormat sdf = new SimpleDateFormat(" yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date());
String outputLog = sb.append(date).append("\r\n").toString();
// 检查文件大小
while (!checkFileInSize(file, limitSize)) {
// 先删除前三行
removeFileLine(file, removeLineNum);
}
// 追加項目啓動log日志
appendContentToFile(file, outputLog);
} catch (FileNotFoundException e) {
logger.error("StartupLog Listener error,{}", e);
} catch (IOException e) {
logger.error("StartupLog Listener error,{}", e);
}
}
}
至此需求已完成。通过此次需求,学习了RandomAccessFile随机文件流的一些简单使用方式,记录在此。
网友评论