basis

Listening for changes (delete, add, modify) in a folder has become much easier since JDK7 added NIO.

public static void makeWatch(Path targetPath, Consumer<Path> consumer){ try { WatchService watchService = targetPath.getFileSystem().newWatchService(); Register (watchService, watchService) with targetPath.register(watchService, watchService, 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(); }}Copy the code

The problem

There are two problems with this code

  1. Only files (folders) below targetPath can be listened on. If files such as targetPath/a/c.txt are created, they will not be listened on.

    WalkFileTree (targetPath, watchService files. walkFileTree, 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; }});Copy the code
  2. The above code fixes problem 1, but if we add a subfolder targetPath/a/b at project runtime, our watchService will fail again if we add files to B. So we need to register this path with the watchService when listening for folder creation

    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)){// note that watchEvent.context() has only one file name. Watchable. Register (watchService) StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE); }}}Copy the code

The complete code

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