mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add WatchServer
This commit is contained in:
parent
41b578391b
commit
9029b10a52
@ -776,6 +776,7 @@ public class CollUtil {
|
||||
} else if (collectionType.isAssignableFrom(LinkedHashSet.class)) {
|
||||
list = new LinkedHashSet<>();
|
||||
} else if (collectionType.isAssignableFrom(TreeSet.class)) {
|
||||
//noinspection SortedCollectionWithNonComparableKeys
|
||||
list = new TreeSet<>();
|
||||
} else if (collectionType.isAssignableFrom(EnumSet.class)) {
|
||||
list = (Collection<T>) EnumSet.noneOf((Class<Enum>) ClassUtil.getTypeArgument(collectionType));
|
||||
@ -2082,7 +2083,7 @@ public class CollUtil {
|
||||
list.addAll(coll);
|
||||
}
|
||||
if (null != comparator) {
|
||||
Collections.sort(list, comparator);
|
||||
list.sort(comparator);
|
||||
}
|
||||
|
||||
return page(pageNo, pageSize, list);
|
||||
@ -2130,7 +2131,7 @@ public class CollUtil {
|
||||
*/
|
||||
public static <T> List<T> sort(Collection<T> collection, Comparator<? super T> comparator) {
|
||||
List<T> list = new ArrayList<>(collection);
|
||||
Collections.sort(list, comparator);
|
||||
list.sort(comparator);
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -2144,7 +2145,7 @@ public class CollUtil {
|
||||
* @see Collections#sort(List, Comparator)
|
||||
*/
|
||||
public static <T> List<T> sort(List<T> list, Comparator<? super T> c) {
|
||||
Collections.sort(list, c);
|
||||
list.sort(c);
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -2224,7 +2225,7 @@ public class CollUtil {
|
||||
*/
|
||||
public static <K, V> LinkedHashMap<K, V> sortToMap(Collection<Map.Entry<K, V>> entryCollection, Comparator<Map.Entry<K, V>> comparator) {
|
||||
List<Map.Entry<K, V>> list = new LinkedList<>(entryCollection);
|
||||
Collections.sort(list, comparator);
|
||||
list.sort(comparator);
|
||||
|
||||
LinkedHashMap<K, V> result = new LinkedHashMap<>();
|
||||
for (Map.Entry<K, V> entry : list) {
|
||||
@ -2258,7 +2259,7 @@ public class CollUtil {
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static <K, V> List<Entry<K, V>> sortEntryToList(Collection<Entry<K, V>> collection) {
|
||||
List<Entry<K, V>> list = new LinkedList<>(collection);
|
||||
Collections.sort(list, (o1, o2) -> {
|
||||
list.sort((o1, o2) -> {
|
||||
V v1 = o1.getValue();
|
||||
V v2 = o2.getValue();
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
package cn.hutool.core.io.watch;
|
||||
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchEvent;
|
||||
|
||||
/**
|
||||
* 监听事件类型枚举,包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1. 事件丢失 OVERFLOW -》StandardWatchEventKinds.OVERFLOW
|
||||
* 2. 修改事件 MODIFY -》StandardWatchEventKinds.ENTRY_MODIFY
|
||||
* 3. 创建事件 CREATE -》StandardWatchEventKinds.ENTRY_CREATE
|
||||
* 4. 删除事件 DELETE -》StandardWatchEventKinds.ENTRY_DELETE
|
||||
* </pre>
|
||||
*
|
||||
* @author loolly
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public enum WatchKind {
|
||||
|
||||
/**
|
||||
* 事件丢失
|
||||
*/
|
||||
OVERFLOW(StandardWatchEventKinds.OVERFLOW),
|
||||
/**
|
||||
* 修改事件
|
||||
*/
|
||||
MODIFY(StandardWatchEventKinds.ENTRY_MODIFY),
|
||||
/**
|
||||
* 创建事件
|
||||
*/
|
||||
CREATE(StandardWatchEventKinds.ENTRY_CREATE),
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
DELETE(StandardWatchEventKinds.ENTRY_DELETE);
|
||||
|
||||
private WatchEvent.Kind<?> value;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param value 事件类型
|
||||
*/
|
||||
WatchKind(WatchEvent.Kind<?> value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取枚举对应的事件类型
|
||||
*
|
||||
* @return 事件类型值
|
||||
*/
|
||||
public WatchEvent.Kind<?> getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -318,7 +318,7 @@ public class WatchMonitor extends Thread implements Closeable, Serializable {
|
||||
* <pre>
|
||||
* maxDepth <= 1 表示只监听当前目录
|
||||
* maxDepth = 2 表示监听当前目录以及下层目录
|
||||
* maxDepth = 3 表示监听当前目录以及下层
|
||||
* maxDepth = 3 表示监听当前目录以及下两层
|
||||
* </pre>
|
||||
*
|
||||
* @param path 字符串路径
|
||||
|
@ -0,0 +1,173 @@
|
||||
package cn.hutool.core.io.watch;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Filter;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.nio.file.AccessDeniedException;
|
||||
import java.nio.file.ClosedWatchServiceException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件监听服务,此服务可以同时监听多个路径。
|
||||
*
|
||||
* @author loolly
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public class WatchServer extends Thread implements Closeable, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 监听服务
|
||||
*/
|
||||
private WatchService watchService;
|
||||
/**
|
||||
* 监听事件列表
|
||||
*/
|
||||
private WatchEvent.Kind<?>[] events;
|
||||
/**
|
||||
* 监听选项,例如监听频率等
|
||||
*/
|
||||
private WatchEvent.Modifier[] modifiers;
|
||||
/**
|
||||
* 监听是否已经关闭
|
||||
*/
|
||||
private boolean isClosed;
|
||||
/**
|
||||
* WatchKey 和 Path的对应表
|
||||
*/
|
||||
private Map<WatchKey, Path> watchKeyPathMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 初始化<br>
|
||||
* 初始化包括:
|
||||
* <pre>
|
||||
* 1、解析传入的路径,判断其为目录还是文件
|
||||
* 2、创建{@link WatchService} 对象
|
||||
* </pre>
|
||||
*
|
||||
* @throws WatchException 监听异常,IO异常时抛出此异常
|
||||
*/
|
||||
public void init() throws WatchException {
|
||||
//初始化监听
|
||||
try {
|
||||
watchService = FileSystems.getDefault().newWatchService();
|
||||
} catch (IOException e) {
|
||||
throw new WatchException(e);
|
||||
}
|
||||
|
||||
isClosed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置监听选项,例如监听频率等,可设置项包括:
|
||||
*
|
||||
* <pre>
|
||||
* 1、com.sun.nio.file.StandardWatchEventKinds
|
||||
* 2、com.sun.nio.file.SensitivityWatchEventModifier
|
||||
* </pre>
|
||||
*
|
||||
* @param modifiers 监听选项,例如监听频率等
|
||||
*/
|
||||
public void setModifiers(WatchEvent.Modifier[] modifiers) {
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定路径加入到监听中
|
||||
*
|
||||
* @param path 路径
|
||||
* @param maxDepth 递归下层目录的最大深度
|
||||
*/
|
||||
public void registerPath(Path path, int maxDepth) {
|
||||
try {
|
||||
final WatchKey key;
|
||||
if (ArrayUtil.isEmpty(this.modifiers)) {
|
||||
key = path.register(this.watchService, this.events);
|
||||
} else {
|
||||
key = path.register(this.watchService, this.events, 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 (false == (e instanceof AccessDeniedException)) {
|
||||
throw new WatchException(e);
|
||||
}
|
||||
|
||||
//对于禁止访问的目录,跳过监听
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行事件获取并处理
|
||||
*
|
||||
* @param watcher {@link Watcher}
|
||||
* @param watchFilter 监听过滤接口,通过实现此接口过滤掉不需要监听的情况,null表示不过滤
|
||||
*/
|
||||
public void watch(Watcher watcher, Filter<WatchEvent<?>> watchFilter) {
|
||||
WatchKey wk;
|
||||
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 != watchFilter && false == watchFilter.accept(event)) {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭监听
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
isClosed = true;
|
||||
IoUtil.close(watchService);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user