javawatchservice

How to watch a folder and subfolders for changes


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?


Solution

  • A WatchService only watches the Paths 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.