问题
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 WatchService
for this but it only watches a single path, it doesn't handle subfolders.
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:
FileA (Created)
FileB
FileC
FolderA FileE
FolderA FolderB FileF
Example 2:
FileA
FileB (Modified)
FileC
FolderA FileE
FolderA FolderB FileF
Is there any better solution?
回答1:
A WatchService
only watches the Path
s you register. It does not go through those paths recursively.
Given /Root
as a registered path
/Root
/Folder1
/Folder2
/Folder3
If there is a change in Folder3
, it won't catch it.
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 WatchService
will notify all changes in all subfolders of Path root
, ie. the Path
argument you pass.
回答2:
Registering recursively will work as Sotirios has indicated. This effectively registers each directory/sub-directory that currently exists.
You can alternatively import and use *com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE* as in:
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.
回答3:
I have implemented something like this using Java 8 streams and lambdas.
The recursive folder discovery is implemented as a 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);
}
};
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.
来源:https://stackoverflow.com/questions/18701242/how-to-watch-a-folder-and-subfolders-for-changes