Search code examples
javafilefilesystemsniofilesystemwatcher

Watching for file and directory changes in Java


I'm writing here mostly for advice on where to start. I've already implemented a class that will recursively watch a directory using Java's WatchService. It works quite alright for detecting changes, but I've noticed a fatal flaw: I cannot delete directories that are being watched that contain directories that are being watched. This seems to be a limitation of WatchService.

I have also looked into Apache's VFS FileListener a bit, but before I spend another 6-or-so hours of my time building some kind of wrapper around it, I figured maybe I'd just ask those more knowledgeable than myself.

I need the directories being watched to be fully manipulable, with the exception that the root directory being watched will not be deleted or renamed. Does there already exist a good class I can work with to monitor files and directories that does not lock files or folders? I'm trying to avoid a polling/hash comparison approach, but I feel more and more as if I will need to use that approach and burn through a ton of CPU resources. Where do I start with this? Ideally, I need to:

-Detect creation of files and directories -Detect deletion of files and directories -Detect renaming of files and directories -Detect modification of files -Detect movement of files between directories

I've also seen some suggest that watchers are unreliable and that they use a combination of the two (polling occasionally in case the watcher failed somewhere), but man that sounds like a real pain that I'd rather avoid if it isn't the best way anyways. I have a feeling I'll need polling and hashing, especially since I want to detect moving and renaming of files, but please do tell if better options exist.

Thanks in advance, and sorry for the not-so-code-specific question!


Solution

  • This will allow you to experiment with creating, deleting, moving and renaming files under D:\Temp, and should allow you to learn what you need:

    import static com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE;
    import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
    import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
    import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
    
    import java.nio.file.FileSystem;
    import java.nio.file.FileSystems;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.WatchEvent;
    import java.nio.file.WatchKey;
    import java.nio.file.WatchService;
    
    public class Foo3
    {
        public static void main(String[] args) throws Exception
        {
            FileSystem fs = FileSystems.getDefault();
            WatchService ws = fs.newWatchService();
            Path pTemp = Paths.get("D:/Temp");
            pTemp.register(ws, new WatchEvent.Kind[] {ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE}, FILE_TREE);
            while(true)
            {
                WatchKey k = ws.take();
                for (WatchEvent<?> e : k.pollEvents())
                {
                    Object c = e.context();
                    System.out.printf("%s %d %s\n", e.kind(), e.count(), c);
                }
                k.reset();
            }
        }
    }