fix watch

This commit is contained in:
Looly 2019-12-09 17:48:25 +08:00
parent dc94761c43
commit a5e9f119b6
3 changed files with 13 additions and 136 deletions

View File

@ -2,23 +2,22 @@ package cn.hutool.core.io.watch;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.watch.watchers.WatcherChain; import cn.hutool.core.io.watch.watchers.WatcherChain;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.file.*; import java.nio.file.Files;
import java.util.EnumSet; import java.nio.file.LinkOption;
import java.util.HashMap; import java.nio.file.Path;
import java.util.Map; import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchService;
/** /**
* 路径监听器 * 路径监听器
@ -30,7 +29,7 @@ import java.util.Map;
* *
* @author Looly * @author Looly
*/ */
public class WatchMonitor extends Thread implements Closeable, Serializable { public class WatchMonitor extends WatchServer {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@ -72,33 +71,10 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
*/ */
private Path filePath; private Path filePath;
/**
* 监听服务
*/
private WatchService watchService;
/** /**
* 监听器 * 监听器
*/ */
private Watcher watcher; private Watcher watcher;
/**
* 监听事件列表
*/
private WatchEvent.Kind<?>[] events;
/**
* 监听选项例如监听频率等
*/
private WatchEvent.Modifier[] modifiers;
/**
* 监听是否已经关闭
*/
private boolean isClosed;
/**
* WatchKey Path的对应表
*/
private Map<WatchKey, Path> watchKeyPathMap = new HashMap<>();
//------------------------------------------------------ Static method start //------------------------------------------------------ Static method start
/** /**
@ -369,14 +345,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
this.path = this.filePath.getParent(); this.path = this.filePath.getParent();
} }
//初始化监听 super.init();
try {
watchService = FileSystems.getDefault().newWatchService();
} catch (IOException e) {
throw new WatchException(e);
}
isClosed = false;
} }
/** /**
@ -441,31 +410,6 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
return this; return this;
} }
/**
* 设置监听选项例如监听频率等可设置项包括
*
* <pre>
* 1com.sun.nio.file.StandardWatchEventKinds
* 2com.sun.nio.file.SensitivityWatchEventModifier
* </pre>
*
* @param modifiers 监听选项例如监听频率等
* @return this
*/
public WatchMonitor setModifiers(WatchEvent.Modifier[] modifiers) {
this.modifiers = modifiers;
return this;
}
/**
* 关闭监听
*/
@Override
public void close() {
isClosed = true;
IoUtil.close(watchService);
}
//------------------------------------------------------ private method start //------------------------------------------------------ private method start
/** /**
@ -474,36 +418,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
* @param watcher {@link Watcher} * @param watcher {@link Watcher}
*/ */
private void doTakeAndWatch(Watcher watcher) { private void doTakeAndWatch(Watcher watcher) {
WatchKey wk; super.watch(watcher, watchEvent -> null == filePath || filePath.endsWith(watchEvent.context().toString()));
try {
wk = watchService.take();
} catch (InterruptedException | ClosedWatchServiceException e) {
// 用户中断
return;
}
final Path currentPath = watchKeyPathMap.get(wk);
WatchEvent.Kind<?> kind;
for (WatchEvent<?> event : wk.pollEvents()) {
kind = event.kind();
// 如果监听文件检查当前事件是否与所监听文件关联
if (null != this.filePath && false == this.filePath.endsWith(event.context().toString())) {
// log.debug("[{}] is not fit for [{}], pass it.", event.context(), this.filePath.getFileName());
continue;
}
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
watcher.onCreate(event, currentPath);
} else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {
watcher.onModify(event, currentPath);
} else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
watcher.onDelete(event, currentPath);
} else if (kind == StandardWatchEventKinds.OVERFLOW) {
watcher.onOverflow(event, currentPath);
}
}
wk.reset();
} }
/** /**
@ -512,43 +427,5 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
private void registerPath() { private void registerPath() {
registerPath(this.path, (null != this.filePath) ? 0 : this.maxDepth); registerPath(this.path, (null != this.filePath) ? 0 : this.maxDepth);
} }
/**
* 将指定路径加入到监听中
*
* @param path 路径
* @param maxDepth 递归下层目录的最大深度
*/
private void registerPath(Path path, int maxDepth) {
final WatchEvent.Kind<?>[] kinds = ArrayUtil.defaultIfEmpty(this.events, EVENTS_ALL);
try {
final WatchKey key;
if (ArrayUtil.isEmpty(this.modifiers)) {
key = path.register(this.watchService, kinds);
} else {
key = path.register(this.watchService, kinds, this.modifiers);
}
watchKeyPathMap.put(key, path);
// 递归注册下一层层级的目录
if (maxDepth > 1) {
//遍历所有子目录并加入监听
Files.walkFileTree(path, EnumSet.noneOf(FileVisitOption.class), maxDepth, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
registerPath(dir, 0);//继续添加目录
return super.postVisitDirectory(dir, exc);
}
});
}
} catch (IOException e) {
if (e instanceof AccessDeniedException) {
//对于禁止访问的目录跳过监听
return;
}
throw new WatchException(e);
}
}
//------------------------------------------------------ private method end //------------------------------------------------------ private method end
} }

View File

@ -39,7 +39,7 @@ public class WatchServer extends Thread implements Closeable, Serializable {
/** /**
* 监听事件列表 * 监听事件列表
*/ */
private WatchEvent.Kind<?>[] events; protected WatchEvent.Kind<?>[] events;
/** /**
* 监听选项例如监听频率等 * 监听选项例如监听频率等
*/ */
@ -47,7 +47,7 @@ public class WatchServer extends Thread implements Closeable, Serializable {
/** /**
* 监听是否已经关闭 * 监听是否已经关闭
*/ */
private boolean isClosed; protected boolean isClosed;
/** /**
* WatchKey Path的对应表 * WatchKey Path的对应表
*/ */

View File

@ -44,7 +44,7 @@ public class WatchMonitorTest {
} }
}; };
WatchMonitor monitor = WatchMonitor.createAll("d:/aaa/aaa.txt", new DelayWatcher(watcher, 500)); WatchMonitor monitor = WatchMonitor.createAll("d:/test/aaa.txt", new DelayWatcher(watcher, 500));
monitor.setMaxDepth(0); monitor.setMaxDepth(0);
monitor.start(); monitor.start();