Java 怎样监控目录的变化

1.需求

监控日志文件的变化,然后存储到数据库

**实现思路 **

1、在程序 首次启动时获取该文件的最后修改时间并且做文件的首次解析,然后每隔一段指定的时间检查一次文件最后被修改的时间,如果与记录的时间相等则等待下次 的采集,否则进行新一轮的采集并且更新时间。

上述的实现方式存在的问题

比如在采集时间间隔内,如果文件发生了N此变化,我只能获取到最后一次,其根本原因是文件的变化不会通知到应用程序,所以只能比较笨的主动去轮询;

2.JDK 1.7 提供了WatchService 类,该类可以基于事件通知的方式监控文件或者目录的任何变化,文件的改变相当于每一个事件(Event)的发生,针对不同的 时间执行不同的动作.

2.代码实现

在创建watchService之后将文件的修改、删除、创建等注册给了WatchService,在指定目录下发生诸如此类的事件之后便会收到通知,我们将事件类型和发生变化的文件Path 封装成FileChangeEvent提交给Event Bus

public class DirectoryTargetMonitor {
     
    private WatchService watchService;

    private final EventBus eventBus;

    private final Path path;

    private volatile boolean start = false;

    public DirectoryTargetMonitor(final EventBus eventBus,final String targetPath){
     
        this(eventBus,targetPath,"");
    }

    public DirectoryTargetMonitor(final EventBus eventBus,final String targetPath,final String... morePaths){
     
        this.eventBus = eventBus;
        this.path = Paths.get(targetPath,morePaths);
    }

    public void startMonitor() throws Exception {
     
        this.watchService = FileSystems.getDefault().newWatchService();
        //为路径注册感兴趣的事件
        this.path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_CREATE);
        System.out.printf("The Directory [%s] is monitoring ...\n", path);
        this.start = true;
        while (start) {
     
            WatchKey watchKey = null;
            try {
     
                /**
                 * 当有事件发生时会 返回对应的WatchKey
                 */
                watchKey = watchService.take();
                watchKey.pollEvents().forEach(event -> {
     
                    WatchEvent.Kind<?> kind = event.kind();
                    Path path = (Path) event.context();
                    Path child = DirectoryTargetMonitor.this.path.resolve(path);
                    //提交FileChangeEvent 到 EventBus
                    eventBus.post(new FileChangeEvent(child, kind));
                });
            } catch (InterruptedException e) {
     
                e.printStackTrace();
                this.start = false;
            } finally {
     
                if (watchKey != null) {
     
                    watchKey.reset();
                }
            }
        }
    }

        public void stopMoitor() throws Exception{
     
           Thread.currentThread().interrupt();
           this.start = false;
           this.watchService.close();
        }
}

public class FileChangeEvent {
     

    private final Path path;

    private final WatchEvent.Kind<?> kind;

    public FileChangeEvent( Path path, WatchEvent.Kind<?> kind ) {
     
        this.kind = kind;
        this.path = path;
    }
    public Path getPath( ) {
     
        return path;
    }
    public WatchEvent.Kind<?> getKind( ) {
     
        return kind;
    }
}

public class FileChangeListener {
     
    @Subscribe
    public void onChange(FileChangeEvent event){
     
        System.out.printf("%s-#s",event.getPath(),event.getKind());
        System.out.println();
    }
}

public class Test {
     
    public static void main( String[] args ) throws Exception{
     
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*2);
        final EventBus eventBus = new AsyncEventBus(executor);
        //注册
        eventBus.register(new FileChangeListener());

        DirectoryTargetMonitor monitor = new DirectoryTargetMonitor(eventBus,"D:\\Test");
        monitor.startMonitor();
    }
}

史上最全的并发编程脑图:https://www.processon.com/view/5f472fd25653bb576974908f

你可能感兴趣的:(各个场景解决方案,监控目录变化)