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();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_31871635/article/details/81164285