为什么WatchService会产生如此多的操作?

时间:2013-04-21 16:44:54

标签: java nio java-7 watchservice

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

当我运行它然后打开Notepad ++然后创建一个新的空文件并将其保存为a.txt目录中我得到了输出:

C:\tmp\

为什么?看起来文件已创建然后被删除然后再次创建。为什么呢?

当我在文件中放入一些文本并保存时,输出为:

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

为什么会改变两次?

4 个答案:

答案 0 :(得分:1)

Watch Service的Modify事件会生成两个事件。当我们修改现有文件时,文件系统首先使用0字节创建它并触发修改事件然后在其上写入数据。然后它再次触发修改事件。这就是它显示两个修改事件的原因。所以我已经做了什么来解决这个问题,我只是使用计数器来检查我的任务应该只在偶数上触发一​​次

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

        }    

答案 1 :(得分:0)

文件创建和删除事件在我的系统中正常工作(Window 7 + 1.7.0_21)。

更改事件消息显示该文件上每个 Ctrl + s 操作的时间(n)。

      // 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();

示例:        如果我们打开文件并继续按下crtl + s(保存没有任何更改/更改)。对于每个保存操作,将显示(重复)以下消息。

     File YourFileName.txt is changed!

原因是在Windows中,WatchService将文件更改与时间戳而不是校验和进行比较。

此处提供更多说明Platform dependencies

答案 2 :(得分:0)

这对我有用

    // 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();
    }

答案 3 :(得分:0)

我创建了一个小的FileWatcher实用程序库: https://github.com/finsterwalder/fileutils

允许设置宽限期。宽限期内的多个事件将被累积并仅触发一次。

您不应该使用Notepad ++进行实验,因为您不知道Notepad ++正在做什么。可能是,Notepad ++实际上是多次写入文件。或者它可以写一个具有不同名称的文件并重命名,完成后或诸如此类的东西。 编写自己的代码来操作文件并观察它。