java实时监控文件行尾内容的实现
今天讲一下怎样用Java实现实时的监控文件行尾的追加内容,类似Linux命令
tail-f
在之前的面试中遇到过一个问题,就是用Java实现tail功能,之前的做法是做一个定时任务每隔1秒去读取一次文件,去判断内容是否有追加,如果有则输出新追加的内容,这个做法虽然能勉强实现功能,但是有点太low,今天采用另外一种实现方式,基于事件通知。
1.WatchService
首先介绍一下WatchService类,WatchService可以监控某一个目录下的文件的变动(新增,修改,删除)并以事件的形式通知文件的变更,这里我们可以实时的获取到文件的修改事件,然后计算出追加的内容,Talkischeap,Showmethecode.
Listener
简单的接口,只有一个fire方法,当事件发生时处理事件。
publicinterfaceListener{
/**
*发生文件变动事件时的处理逻辑
*
*@paramevent
*/
voidfire(FileChangeEventevent);
}
FileChangeListener
Listener接口的实现类,处理文件变更事件。
publicclassFileChangeListenerimplementsListener{
/**
*保存路径跟文件包装类的映射
*/
privatefinalMapmap=newConcurrentHashMap<>();
publicvoidfire(FileChangeEventevent){
switch(event.getKind().name()){
case"ENTRY_MODIFY":
//文件修改事件
modify(event.getPath());
break;
default:
thrownewUnsupportedOperationException(
String.format("Thekind[%s]isunsupport.",event.getKind().name()));
}
}
privatevoidmodify(Pathpath){
//根据全路径获取包装类对象
FileWrapperwrapper=map.get(path.toString());
if(wrapper==null){
wrapper=newFileWrapper(path.toFile());
map.put(path.toString(),wrapper);
}
try{
//读取追加的内容
newContentReader(wrapper).read();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
FileWrapper
文件包装类,包含文件和当前读取的行号
publicclassFileWrapper{
/**
*当前文件读取的行数
*/
privateintcurrentLine;
/**
*监听的文件
*/
privatefinalFilefile;
publicFileWrapper(Filefile){
this(file,0);
}
publicFileWrapper(Filefile,intcurrentLine){
this.file=file;
this.currentLine=currentLine;
}
publicintgetCurrentLine(){
returncurrentLine;
}
publicvoidsetCurrentLine(intcurrentLine){
this.currentLine=currentLine;
}
publicFilegetFile(){
returnfile;
}
}
FileChangeEvent
文件变更事件
publicclassFileChangeEvent{
/**
*文件全路径
*/
privatefinalPathpath;
/**
*事件类型
*/
privatefinalWatchEvent.Kind>kind;
publicFileChangeEvent(Pathpath,Kind>kind){
this.path=path;
this.kind=kind;
}
publicPathgetPath(){
returnthis.path;
}
publicWatchEvent.Kind>getKind(){
returnthis.kind;
}
}
ContentReader
内容读取类
publicclassContentReader{
privatefinalFileWrapperwrapper;
publicContentReader(FileWrapperwrapper){
this.wrapper=wrapper;
}
publicvoidread()throwsFileNotFoundException,IOException{
try(LineNumberReaderlineReader=newLineNumberReader(newFileReader(wrapper.getFile()))){
Listcontents=lineReader.lines().collect(Collectors.toList());
if(contents.size()>wrapper.getCurrentLine()){
for(inti=wrapper.getCurrentLine();i
DirectoryTargetMonitor
目录监视器,监控目录下文件的变化
publicclassDirectoryTargetMonitor{
privateWatchServicewatchService;
privatefinalFileChangeListenerlistener;
privatefinalPathpath;
privatevolatilebooleanstart=false;
publicDirectoryTargetMonitor(finalFileChangeListenerlistener,finalStringtargetPath){
this(listener,targetPath,"");
}
publicDirectoryTargetMonitor(finalFileChangeListenerlistener,finalStringtargetPath,finalString...morePaths){
this.listener=listener;
this.path=Paths.get(targetPath,morePaths);
}
publicvoidstartMonitor()throwsIOException{
this.watchService=FileSystems.getDefault().newWatchService();
//注册变更事件到WatchService
this.path.register(watchService,StandardWatchEventKinds.ENTRY_MODIFY);
this.start=true;
while(start){
WatchKeywatchKey=null;
try{
//阻塞直到有事件发生
watchKey=watchService.take();
watchKey.pollEvents().forEach(event->{
WatchEvent.Kind>kind=event.kind();
Pathpath=(Path)event.context();
Pathchild=this.path.resolve(path);
listener.fire(newFileChangeEvent(child,kind));
});
}catch(Exceptione){
this.start=false;
}finally{
if(watchKey!=null){
watchKey.reset();
}
}
}
}
publicvoidstopMonitor()throwsIOException{
System.out.printf("Thedirectory[%s]monitorwillbestop...\n",path);
Thread.currentThread().interrupt();
this.start=false;
this.watchService.close();
System.out.printf("Thedirectory[%s]monitorwillbestopdone.\n",path);
}
}
测试类
在D盘新建一个monitor文件夹,新建一个test.txt文件,然后启动程序,程序启动完成后,我们尝试往test.txt添加内容然后保存,控制台会实时的输出我们追加的内容,PS:追加的内容要以新起一行的形式追加,如果只是在原来的尾行追加,本程序不会输出到控制台,有兴趣的同学可以扩展一下
publicstaticvoidmain(String[]args)throwsIOException{
DirectoryTargetMonitormonitor=newDirectoryTargetMonitor(newFileChangeListener(),"D:\\monitor");
monitor.startMonitor();
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。