以下demo 可以监控D:\demo 及其子目录下的文件变动(增删改查)
我是尝试用它监控本地报文,但是在多线程往这个文件夹写入文件的时候
watchservice会发生漏扫描的情况,漏掉的往往是每个线程创建的第一个文件。
监控类:
package com.example.watchservice;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
public class TestWatchService {
private final WatchService watcher;
private final Map<WatchKey, Path> keys; //所有监控的目录,和监控他们的key
private volatile int n = 0;
/**
* 创建一个 WatchService 并注册给定的目录
*/
TestWatchService(Path dir) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey, Path>();
walkAndRegisterDirectories(dir);
}
/**
* 使用 WatchService 注册给定的目录;这个函数会被 FileVisitor 调用
*/
private void registerDirectory(Path dir) throws IOException
{
//监控文件,事件为增删改
WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds. ENTRY_MODIFY);
keys.put(key, dir);
}
/**
* 使用 WatchService 注册给定目录及其所有子目录。
*/
private void walkAndRegisterDirectories(final Path start) throws IOException {
// 注册目录和子目录
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerDirectory(dir);
return FileVisitResult.CONTINUE;
}
});
}
/**
* 处理排队等待观察者的键的所有事件
*/
void processEvents() {
for (int enterTimes = 0; ;enterTimes++) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
Path dir = keys.get(key);
if (dir == null) {
System.err.println("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event : key.pollEvents()) {
@SuppressWarnings("rawtypes")
WatchEvent.Kind kind = event.kind();
// 目录条目事件的上下文是条目的文件名
@SuppressWarnings("unchecked")
Path name = ((WatchEvent<Path>)event).context();
Path child = dir.resolve(name);
System.out.format("EnterTimes:%5d %s->No %-5d: %s\n",enterTimes, event.kind().name(),++n, child);
if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
try {
if (Files.isDirectory(child)) { // 如果目录已创建,并递归查看,则注册它及其子目录
walkAndRegisterDirectories(child);
}
} catch (IOException x) {
// do something useful
}
}
}
// 如果目录不再可访问,则重置密钥并从集合中删除
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// 所有目录都无法访问
if (keys.isEmpty()) {
break;
}
}
}
}
public static void main(String[] args) throws IOException {
Path dir = Paths.get("D:\\demo");
new TestWatchService(dir).processEvents();
}
}
文件创建类:
public class FileCreator {
/**
* 启动多线程创建文件
* @param args
*/
public static void main(String[] args) {
final String rootPath = "D:\\IdeaProjects\\MESSAGE\\SzjgHTH";
final int count = 10000;
final ExecutorService exec = Executors.newFixedThreadPool(4);
ExecutorService executorService = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
for (int i = 0; i < count; i++) {
int finalI = i;
exec.execute(() -> {
writeFile("hello",rootPath+"\\hello\\"+ finalI +".txt");
});
}
}
public static void writeFile(String content, String path) {
PrintWriter output = null;
try {
//判断路径是否存在,不存在则创建
String abPath = path.substring(0, path.lastIndexOf("\\"));
File file = new File(abPath);
mkdirs(file);
output = new PrintWriter(new OutputStreamWriter(new FileOutputStream(path), StandardCharsets.UTF_8));
output.println(content);
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
//创建目录
public static boolean mkdirs(File file){
boolean success;
if(!file.exists()){ //不存在 则创建
if(!file.exists()){
// 同步 :不存在 则创建
success = file.mkdirs();
}else {
//否则就是已创建
success = true;
}
}else {
//否则就是已创建
success = true;
}
return success;
}
}