Java 如何查看文件夹和子文件夹的更改
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18701242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to watch a folder and subfolders for changes
提问by Yuri Heupa
I′m trying to watch a specific folder for changes, and then if any addition/edition/removal happens inside of it, I need to get the change type of all files in that folder and its subfolders. I'm using WatchServicefor this but it only watches a single path, it doesn't handle subfolders.
我正在尝试查看特定文件夹的更改,然后如果其中发生任何添加/编辑/删除,我需要获取该文件夹及其子文件夹中所有文件的更改类型。我正在使用WatchService它,但它只监视一条路径,它不处理子文件夹。
Here's my approach:
这是我的方法:
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;
}
Like I said before, I'm getting the log only for the files in the selected path, and I want to watch all folders and subfolders files, something like:
就像我之前说的,我只获取所选路径中文件的日志,我想查看所有文件夹和子文件夹文件,例如:
Example 1:
示例 1:
FileA (Created)
FileB
FileC
FolderA FileE
FolderA FolderB FileF
Example 2:
示例 2:
FileA
FileB (Modified)
FileC
FolderA FileE
FolderA FolderB FileF
Is there any better solution?
有没有更好的解决办法?
采纳答案by Sotirios Delimanolis
A WatchServiceonly watches the Paths you register. It does not go through those paths recursively.
AWatchService只看Path你注册的s。它不会递归地通过这些路径。
Given /Rootas a registered path
鉴于/Root作为注册路径
/Root
/Folder1
/Folder2
/Folder3
If there is a change in Folder3, it won't catch it.
如果 有变化Folder3,它就不会捕捉到它。
You can register the directory paths recursively yourself with
您可以自己递归注册目录路径
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;
}
});
}
Now the WatchServicewill notify all changes in all subfolders of Path root, ie. the Pathargument you pass.
现在WatchService将通知 的所有子文件夹中的所有更改Path root,即。Path你通过的论点。
回答by mjash
Registering recursively will work as Sotirios has indicated. This effectively registers each directory/sub-directory that currently exists.
递归注册将如 Sotirios 所指示的那样工作。这有效地注册了当前存在的每个目录/子目录。
You can alternatively import and use *com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE* as in:
您也可以导入和使用 *com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE*,如下所示:
dir.register(watcher, standardEventsArray, ExtendedWatchEventModifier.FILE_TREE);
This will watch the entire sub-tree for change AND account for added directories and sub-directories.
这将监视整个子树的更改和添加的目录和子目录的帐户。
Otherwise you will have to monitor for any new directories/sub-directories and register them also. There can also be an issue with deleting parts of the directory hierarchy since each registered directory has a handle watching it so the (lowest) sub-directories need to be removed first when deleting parts of the structure.
否则,您将必须监视任何新目录/子目录并同时注册它们。删除部分目录层次结构也可能存在问题,因为每个注册的目录都有一个监视它的句柄,因此在删除部分结构时需要首先删除(最低)子目录。
回答by Fabrizio Fortino
I have implemented something like this using Java 8 streams and lambdas.
我已经使用 Java 8 流和 lambdas 实现了这样的东西。
The recursive folder discovery is implemented as a Consumer@FunctionalInterface:
递归文件夹发现是作为消费者@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);
}
};
The above code is called every time a new folder is created to dynamically add folders at later stages. Full solution and more details here.
每次创建新文件夹时都会调用上面的代码,以便在后期动态添加文件夹。完整的解决方案和更多细节在这里。

