基础
自从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();
}
}