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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。