我正在尝试查看特定文件夹以进行更改,然后如果在其中发生任何添加/编辑/删除,我需要获取该文件夹及其子文件夹中所有文件的更改类型。我正在使用WatchService
,但它只观看单个路径,它不处理子文件夹。
这是我的方法:
try {
WatchService watchService = pathToWatch.getFileSystem().newWatchService();
pathToWatch.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
// loop forever to watch directory
while (true) {
WatchKey watchKey;
watchKey = watchService.take(); // This call is blocking until events are present
// Create the list of path files
ArrayList<String> filesLog = new ArrayList<String>();
if(pathToWatch.toFile().exists()) {
File fList[] = pathToWatch.toFile().listFiles();
for (int i = 0; i < fList.length; i++) {
filesLog.add(fList[i].getName());
}
}
// Poll for file system events on the WatchKey
for (final WatchEvent<?> event : watchKey.pollEvents()) {
printEvent(event);
}
// Save the log
saveLog(filesLog);
if(!watchKey.reset()) {
System.out.println("Path deleted");
watchKey.cancel();
watchService.close();
break;
}
}
} catch (InterruptedException ex) {
System.out.println("Directory Watcher Thread interrupted");
return;
} catch (IOException ex) {
ex.printStackTrace(); // Loggin framework
return;
}
就像我之前说过的那样,我只获取所选路径中的文件的日志,并且我想要查看所有文件夹和子文件夹文件,例如:
示例1:
FileA (Created)
FileB
FileC
FolderA FileE
FolderA FolderB FileF
示例2:
FileA
FileB (Modified)
FileC
FolderA FileE
FolderA FolderB FileF
有没有更好的解决方案?
答案 0 :(得分:18)
WatchService
只会观看您注册的Path
。它不会递归地通过这些路径。
将/Root
作为注册路径
/Root
/Folder1
/Folder2
/Folder3
如果Folder3
发生变化,则不会发现变化。
您可以使用
自行递归注册目录路径private void registerRecursive(final Path root) throws IOException {
// register all subfolders
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
dir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
return FileVisitResult.CONTINUE;
}
});
}
现在WatchService
将通知Path root
所有子文件夹中的所有更改,即。你传递的Path
参数。
答案 1 :(得分:9)
递归注册将像Sotirios指出的那样工作。这有效地注册了当前存在的每个目录/子目录。
您也可以导入和使用* com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE *,如下所示:
dir.register(watcher, standardEventsArray, ExtendedWatchEventModifier.FILE_TREE);
这将监视整个子树的更改并考虑添加的目录和子目录。
否则,您必须监视任何新目录/子目录并注册它们。删除部分目录层次结构也可能存在问题,因为每个注册的目录都有一个句柄,因此在删除结构的某些部分时需要首先删除(最低)子目录。
答案 2 :(得分:5)
我使用Java 8流和lambdas实现了类似的东西。
递归文件夹发现实现为Consumer @FunctionalInterface:
final Map<WatchKey, Path> keys = new HashMap<>();
Consumer<Path> register = p -> {
if (!p.toFile().exists() || !p.toFile().isDirectory()) {
throw new RuntimeException("folder " + p + " does not exist or is not a directory");
}
try {
Files.walkFileTree(p, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
LOG.info("registering " + dir + " in watcher service");
WatchKey watchKey = dir.register(watcher, new WatchEvent.Kind[]{ENTRY_CREATE}, SensitivityWatchEventModifier.HIGH);
keys.put(watchKey, dir);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new RuntimeException("Error registering path " + p);
}
};
每次创建新文件夹时都会调用上面的代码,以便在以后的阶段动态添加文件夹。 完整的解决方案和更多详细信息here。