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?

Pawel P.
  • 3,731
  • 4
  • 20
  • 20
  • 5
    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 (http://technet.microsoft.com/en-gb/sysinternals/bb896653.aspx) to monitor the IO activity at an OS level you will see the same results. – Paul H Apr 21 '13 at 18:36
  • 2
    This might be due to the fact that content and metadata writes are performed separately. – Tadas S Apr 24 '13 at 10:11

4 Answers4

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");
            }

        }    
svarog
  • 9,477
  • 4
  • 61
  • 77
Rohit Luthra
  • 1,256
  • 17
  • 27
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

Xyz
  • 5,955
  • 5
  • 40
  • 58
VKPRO
  • 159
  • 1
  • 3
  • 8
  • 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? – Robin Green Apr 08 '14 at 15:56
  • @RobinGreen, Please tell me what's is your exception and your answer. – VKPRO Apr 11 '14 at 14:31
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();
    }
Kurohige
  • 333
  • 2
  • 10
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.