Monitor subfolders with a Java watch service
Asked Answered
D

4

14

I am using watchKey to listen for a file change in a particular folder.

Path _directotyToWatch = Paths.get("E:/Raja");
WatchService watcherSvc = FileSystems.getDefault().newWatchService();
WatchKey watchKey = _directotyToWatch.register(watcherSvc, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

while (true) {
    watchKey=watcherSvc.take();
    for (WatchEvent<?> event: watchKey.pollEvents()) {
        WatchEvent<Path> watchEvent = castEvent(event);
        System.out.println(event.kind().name().toString() + " " + _directotyToWatch.resolve(watchEvent.context()));
        watchKey.reset();
    }
}


It working fine for me. If I modify a file in raja folder it gives me the file name with path. But, when I put some files in subfolders like "E:/Raja/Test", it gives me only the path where I put it, not the file name.

How to get the file name?

Dealt answered 17/5, 2013 at 14:22 Comment(1)
this is a duplicate of #5608734Howse
P
22

The reason why you're not getting the file name created/modified inside a subfolder is given by Stephen C in his answer.

Here is a simple example of how to register directories and subdirectories to watch them for the events you are interested in:

/**
 * Register the given directory and all its sub-directories with the WatchService.
 */
private void registerAll(final Path start) throws IOException {
    // register directory and sub-directories
    Files.walkFileTree(start, new SimpleFileVisitor<Path>() {

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException {
            dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            return FileVisitResult.CONTINUE;
        }

    });

}

Check out the official Java Tutorials: Watching a Directory for Changes. There you can find very nice explanations and examples with the source code.

Particularly you'll be interested in this example of how to watch a directory (or directory tree) for changes to files: WatchDir.java.

The method I supplied above was taken from this example (omitting some parts for brevity).
Read the tutorial for the details.

Proper answered 17/5, 2013 at 15:47 Comment(2)
I tested the above code and it gives NULL Pointer exception on OpenJDK 11. But OpenJDK has closed this as not an issue mentioning that we can't pass null in constructors. bugs.openjdk.java.net/browse/JDK-8133521Tripping
@Tripping If you look at the source code of the java.nio.file.Paths class you will see, that the get(URI uri) method calls java.nio.file.Path.of(uri) static method, inside which there is no check for null and the uri is immediately used to call getScheme() on it. So no wonder that if uri was null, it will result in NPE. But it's totally unrelated to the OP's question.Proper
H
11

The reason you are only seeing an event for "E:/Raja/Test" and not "E:/Raja/Test/Foo.txt" (for example) is that you've only registered the "E:/Raja" directory with the service. This means you will see events on the directory and its immediate members. The "E:/Raja/Test" is a member of the directory, and you are getting events to say that is has been changed ... when files are added to it.

The solution is to register all of subdirectories of "E:/Raja" as well ... going as far down the directory hierarchy as you need to go.

Housebound answered 17/5, 2013 at 15:36 Comment(2)
If he registers E:/Raha and E:/Raha/Test I think he will get two events fired if E:/Raja/Test/Foo.txt is created.Altruist
Yes he will. But that's not the point. The point is that the event from the watcher on E:/Raha/Test will give him a CREATE event the full pathname of the created file, but the other one will be a MODIFY event giving the pathname of the directory that was modified. (OK ... I'm going from memory ...)Housebound
A
0

I know this is ugly, hopefully somebody has a better answer but you can create a list of every file in every subfolder and there last modified times.

When you receive ENTRY_CREATE or ENTRY_DELETE compare the folder to your list to figure out which file was changed

When you receive a ENTRY_MODIFY compare the last modified times.

Remember to update your list.

Altruist answered 17/5, 2013 at 14:35 Comment(5)
Solution 2 is like saying to your 5 year old to learn how to skateboard because he can't ride a bike. Hardly a solution as both require learning.Howse
No solution 2 is like saying to your 5 year old to lean how to ride a skateboard because he wants a bike with 4 wheels, that he can fit in his book bag, ride in a standing position and store in his school locker. I've done filewatchers in java and C#. C# simply does it betterAltruist
Maybe C# does it better, but the OP maybe need to work with Java, so using C# would not be a solution. I think it's a suggestion rather than a solution.Ionic
I agree it should have been a sugestion I changed it.Altruist
C# should not be a suggestion as the question is specifically about Java. A comment, at best...Scepter
E
0

Scenario:
Upon registering a folder F1, watchService only monitors the changes inside that folder say F1 alone and it will not monitor the changes inside in any of its subfolders F11 or F12 inside the folder F1 registered.

Tho upon changes inside F11 or F12, watchService monitoring F1 will be triggered for a change in respective subFolder, providing you that F11 or F12 has some MODIFY operation but no information about anything inside.

Solution:
We need to register the Folder F1 and all of it subFolders F11 and F12 recursively. And the solution is provided in the official doc itself.

Here's the code segment you need to recursivly folder F1 and all of its subfolder to watchService:

/**
 * Register the given directory and all its sub-directories with the WatchService.
 */
private void registerAll(final Path start) throws IOException {
    // register directory and sub-directories
    Files.walkFileTree(start, new SimpleFileVisitor<Path>() {

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException {
            dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            return FileVisitResult.CONTINUE;
        }

    });

}

Incase of more details or incase you dont understand the usage of this code segment. refer to official doc. links provided below.

Official Doc Ref:
https://docs.oracle.com/javase/tutorial/essential/io/notification.html https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java

Execratory answered 18/2 at 6:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.