Why does WatchService generate so many operations?
Asked Answered
B

4

24
import java.io.*;
import java.nio.file.*;

public class Tmp {

    public static void main(String [] args) throws IOException {
        int count = 0;
        Path path = Paths.get("C:\\tmp\\");
        WatchService ws = null;
        try {
            ws = FileSystems.getDefault().newWatchService();
            path.register(ws, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
                    StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.OVERFLOW);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

        while(true) {
            WatchKey key = null;
            try {
                key = ws.take();
            } catch(InterruptedException ie) {
                ie.printStackTrace();
            }

            for(WatchEvent<?> event: key.pollEvents()) {
                switch(event.kind().name()) {
                    case "OVERFLOW":
                        System.out.println(++count + ": OVERFLOW");
                        break;
                    case "ENTRY_MODIFY":
                        System.out.println(++count + ": File " + event.context() + " is changed!");
                        break;
                    case "ENTRY_CREATE":
                        System.out.println(++count + ": File " + event.context() + " is created!");
                        break;
                    case "ENTRY_DELETE":
                        System.out.println(++count + ": File " + event.context() + " is deleted!");
                        break;
                    default:
                        System.out.println(++count + ": UNKNOWN EVENT!");
                }
            }

            key.reset();
        }    
    }
}

When I run this and then opened the Notepad++ and then created a new empty file and saved it as a.txt in the C:\tmp\ directory I got the output:

1: File a.txt is created!
2: File a.txt is deleted!
3: File a.txt is created!

Why is that? It looks like the file was created and then deleted and then created again. Why?

When I put some text in the file and saved it the output was:

4: File a.txt is changed!
5: File a.txt is changed!

Why did it change twice?

Baziotes answered 21/4, 2013 at 16:44 Comment(2)
I think the behaviour you're seeing with WatchService is due to the way Notepad++ and to some extend the way the Windows operating system works when performing IO operations. I've found that something like the "standard" Windows notepad usually produces the most expected behaviour. I suspect that if you use Process Explorer (technet.microsoft.com/en-gb/sysinternals/bb896653.aspx) to monitor the IO activity at an OS level you will see the same results.Balbur
This might be due to the fact that content and metadata writes are performed separately.Arman
H
2

Watch Service's Modify event generates two events. When we modify an already existing file, the file system first creates it with 0 bytes and fires a modify event and then writes data on it. Then it fires the modify event again. That's why It was showing two modify events. So What I have done to solve this problem, I just use counter to check my task should be triggered only once on even count

        Path path = null;
        int count = 0;

        try {
            path = Paths.get(new Utility().getConfDirPath());
            System.out.println("Path: " + path);
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }

        WatchService watchService = null;
        try {
            watchService = FileSystems.getDefault().newWatchService();
            path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }


        while(true) {
            WatchKey key = null;
            try {
                key = watchService.take();
            } catch(InterruptedException ie) {
                ie.printStackTrace();
            }

            for(WatchEvent<?> event: key.pollEvents()) {
                switch(event.kind().name()) {
                    case "ENTRY_MODIFY":
                        System.out.println(++count + ": File " + event.context() + " is changed!");

                        if (count%2==0) {
                            doOnChange(); // do whatever you want
                        }
                        break;
                    case "ENTRY_DELETE":
                        System.out.println(++count + ": File " + event.context() + " is deleted!");
                        break;
                    default:
                        System.out.println(++count + ": UNKNOWN EVENT!");
                }
            }

            // reset the key
            boolean valid = key.reset();
            if (!valid) {
                System.out.println("Key has been unregistered");
            }

        }    
Humus answered 22/12, 2016 at 7:24 Comment(0)
L
0

The File creation and deletion events are working correctly in my system(Window 7 + 1.7.0_21).

The change event message is displayed number of time's(n) for each Ctrl+s operation on that file.

      // Removed the "//" after director name as D://tmp"
      //Added just to see the message with a 1 ms gap.
      Thread.sleep(1000); // after key.reset();

Example : If we open the file and keep on pressing the crtl + s (save with out any changes/with changes). The following message will display(repeatedly) for each save operation.

     File YourFileName.txt is changed!

Reason is in windows the WatchService is comparing the file changes with timestamp instead of checksum.

More description given here Platform dependencies

Lani answered 19/5, 2013 at 14:6 Comment(2)
That's not a 1ms gap, that's a 1 second gap. Of course you won't see the effect if you wait for a very long time in computer terms before checking again. As for this: "Reason is in windows the WatchService is comparing the file changes with timestamp instead of checksum." uh... what?Feigin
@RobinGreen, Please tell me what's is your exception and your answer.Lani
L
0

this works for me

    // get the first event before looping
    WatchKey key = this.watcher.take();

    // reset key (executed twice but not invoke the polled events)
    while (key != null && key.reset() ) { 
      // polled events
      for (final WatchEvent<?> event : key.pollEvents()) {
        System.out.printf("\nGlobal received: %s, event for file: %s\n", event.kind(),
            event.context());

        switch (event.kind().name()) {
        case "ENTRY_CREATE":
          LOGGER.debug("event ENTRY_CREATE");
          break;
        case "ENTRY_DELETE":
          LOGGER.debug("event ENTRY_DELETE");
          break;
        case "ENTRY_MODIFY":
          LOGGER.debug("event ENTRY_MODIFY");
          break;
        default:
          LOGGER.debug("event other [OVERFLOW]");
          break;
        }
      }

      key = this.watcher.take();
    }
Larder answered 26/9, 2016 at 13:38 Comment(0)
D
0

I created a small FileWatcher Utility Library: https://github.com/finsterwalder/fileutils

It allows to set a grace period. Multiple events inside the grace period are accumulated and only triggered once.

You should not use Notepad++ for your experiments, since you don't know what Notepad++ is doing. It may be, that Notepad++ is actually writing to a file several times. Or it could write a file with a different name and rename it, when done or whatnot. Write your own code to manipulate files and watch that.

Dorian answered 15/3, 2017 at 19:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.