0

When the file structure changes. I keep getting printlns for every single file that was changed. How do I make it so that I only get one println for multiple changes in a 10 second period?

try {
    WatchService watchService = FileSystems.getDefault().newWatchService();
    Path path = new File("C:\\Users\\myuser\\Desktop\\TestFolder").toPath();

    path.register(
        watchService,
        StandardWatchEventKinds.ENTRY_CREATE,
        StandardWatchEventKinds.ENTRY_DELETE,
        StandardWatchEventKinds.ENTRY_MODIFY);

    WatchKey key;

    while ((key = watchService.take()) != null) {
        for (WatchEvent<?> event : key.pollEvents()) {

            System.out.println(
                "Event kind:" + event.kind() + ". File affected: " + event.context() + ".");
            System.out.println("Something changed!");
            Thread.sleep(10000);
            System.out.println("Resuming..");
            break;
        }
        key.reset();
    }
} catch (IOException e) {
    e.printStackTrace();
} catch (InterruptedException e) {
    e.printStackTrace();
}
JustAFellowCoder
  • 300
  • 2
  • 11
Markus Tonsaker
  • 479
  • 5
  • 15
  • You can't without writing additional code. Something like [a debouncer](https://stackoverflow.com/questions/4742210/implementing-debounce-in-java). – Sean Bright Mar 27 '19 at 16:00

3 Answers3

0

Well, you could do something like following, using WatchService.poll(long timeout, TimeUnit unit) and Thread.sleep(10000) combined.

Take a look at this

   /**
     * Method used for tracking corresponding events( create,delete, modify )  
     * for a given directory every 10 seconds.
     * @throws InterruptedException 
     */
    private void monitoringWithTenSecondsLate() throws InterruptedException {
        WatchKey watchKey = null;
        while (true) {
            try {
                //poll everything every 10 seconds
                watchKey = watchService.poll(10, TimeUnit.SECONDS);
                for (WatchEvent<?> watchEvent : watchKey.pollEvents()) {
                    WatchEvent.Kind<?> kind = watchEvent.kind();
                    System.out.println("Event occured for " + watchEvent.context().toString() + " " + kind.toString());
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(WatchServiceExample10SecondsLate.class.getName()).log(Level.SEVERE, null, ex);
            }
            //don't reset watch key for 10 seconds
            Thread.sleep(10000);
            boolean reset = watchKey.reset();
            if (!reset) {
                break;
            }
        }
    }

Full code can be acquired from here: Github Code for WatchService 10 seconds example.

MS90
  • 1,219
  • 1
  • 8
  • 17
0

I'd simply poll all keys and concatenate the result.

Something along the lines of this:

while ((key = watchService.take()) != null) {
    StringJoiner joiner = new StringJoiner(",");
    for (WatchEvent<?> event : key.pollEvents()) {
        joiner.add(event.getContext().toString())        
    }
    key.reset();
    Thread.sleep(10000);

    System.out.println("Resuming ...");
    System.out.println("Something has changed! Affected files:" + joiner.toString())
}
Marcel
  • 1,509
  • 1
  • 17
  • 39
0

So right now, as I understand it, your events while the thread is sleeping get queued and will still be processed. What I suppose you want, from what you wrote, is to still process these events but only print a total list of the events after 10s. In this case, your Thread.sleep() while handling the event isn't a good solution.

What you could do is implement a thread for your watcher that would, for example, add each event it registers to a variable in a thread-safe way for your main thread to access after 10 seconds. So, in your main thread, you'd have a loop which would sleep for 10 seconds and, upon waking up, retrieve this variable, print it out and reset it.

It would be something like this :

private Object lock = new Object(); // defined in your watcher class
private String events = new String() // also defined in your class

thread = new Thread(listeningFunc);
thread.start()

while(True) {
    Thread.sleep(10000);
    syncronized(lock) {
        System.out.println(events);
        events = new String()
    }
}

// With this function defined in your class to run in your new thread
listeningFunc() {

    path.register(
        watchService,
        StandardWatchEventKinds.ENTRY_CREATE,
        StandardWatchEventKinds.ENTRY_DELETE,
        StandardWatchEventKinds.ENTRY_MODIFY);

    WatchKey key;

    while((key = watchService.take()) != null) {
        for (WatchEvent<?> event : key.pollEvents()) {
            syncronized(lock) {
                events += "Event kind:" + event.kind() + ". File affected: " + event.context() + ".\n"
            }
        }
        key.reset()
    }
}
Olivier Samson
  • 609
  • 4
  • 13