基础
自从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();
}
}
复制代码
问题
这段代码有两个问题
-
只能监听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; } }); 复制代码
-
上面的代码虽然解决了问题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();
}
}复制代码