WatchService 监听一个文件夹下所有层的变化 (新添加的文件也能被监听)

基础

自从JDK7 添加了nio之后 监听一个文件夹里的变动(删除,新增,修改)也变得非常简单.

public static void makeWatch(Path targetPath, Consumer<Path> consumer){
    try {
        WatchService watchService = targetPath.getFileSystem().newWatchService();
        //将targetPath注册到watchService,这样这个watchService将会监听到 这个目录下的文件的创建或者删除
        targetPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE);
        ThreadPoolUtils.getInstance().execute(()->{
            WatchKey watchKey = null;
            while (true) {
                try {
                    watchKey = watchService.take();
                    List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
                    for (final WatchEvent<?> event : watchEvents) {
                        WatchEvent<Path> watchEvent = (WatchEvent<Path>) event;
                        WatchEvent.Kind<Path> kind = watchEvent.kind();
                    }
                    //consumer.accept(targetPath);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(watchKey != null){
                        watchKey.reset();
                    }
                }
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}
复制代码

问题

这段代码有两个问题

  1. 只能监听targetPath下一层的文件(夹),如果创建了 targetPath/a/c.txt 这样的文件 就不会被监听到.

         //因此我们将rigister的那段代码修改为 让targetPath下的所有文件夹(多层)都注册到watchService
         Files.walkFileTree(targetPath, new SimpleFileVisitor<Path>() {
             @Override
             public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                     throws IOException
             {
                 dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
                 return FileVisitResult.CONTINUE;
             }
         });
    复制代码
  2. 上面的代码虽然解决了问题1,但是如果我们在项目运行时又添加了一个子文件夹 targetPath/a/b 这样如果在b中添加文件 我们的watchService又傻眼了.所有我们在监听到文件夹创建的时候要给让这个path注册到watchService上

                         for (final WatchEvent<?> event : watchEvents) {
                             WatchEvent<Path> watchEvent = (WatchEvent<Path>) event;
                             WatchEvent.Kind<Path> kind = watchEvent.kind();
                             if(kind == StandardWatchEventKinds.ENTRY_CREATE){
                                 Path watchable = ((Path) watchKey.watchable()).resolve(watchEvent.context());
                                 if(Files.isDirectory(watchable)){
                                     //注意watchEvent.context()这个只有一个文件名(坑爹啊 为啥不给全路径)
                                     watchable.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
                                 }
                             }
                         }
    复制代码

完整代码

    public static void makeWatch(Path targetPath, Consumer<Path> consumer){
    try {
        WatchService watchService = targetPath.getFileSystem().newWatchService();
        Files.walkFileTree(targetPath, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException
            {
                dir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
                return FileVisitResult.CONTINUE;
            }
        });
        ThreadPoolUtils.getInstance().execute(()->{
            WatchKey watchKey = null;
            while (true) {
                try {
                    watchKey = watchService.take();

                    List<WatchEvent<?>> watchEvents = watchKey.pollEvents();
                    for (final WatchEvent<?> event : watchEvents) {
                        WatchEvent<Path> watchEvent = (WatchEvent<Path>) event;
                        WatchEvent.Kind<Path> kind = watchEvent.kind();
                        if(kind == StandardWatchEventKinds.ENTRY_CREATE){
                            Path watchable = (Path) watchKey.watchable();
                            if(Files.isDirectory(watchable)){
                                watchable.resolve(watchEvent.context()).register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
                            }
                        }
                    }
                    consumer.accept(targetPath);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(watchKey != null){
                        watchKey.reset();
                    }
                }
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}复制代码
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值