Подтвердить что ты не робот

Почему 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: File a.txt is changed!
5: File a.txt is changed!

Почему это изменилось дважды?

4b9b3361

Ответ 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");
            }

        }    

Ответ 2

События создания и удаления файлов корректно работают в моей системе (Window 7 + 1.7.0_21).

Сообщение о событии изменения отображает количество времени (n) для каждой операции Ctrl + s в этом файле.

      // 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 сравнивает изменения файлов с меткой времени вместо контрольной суммы.

Подробное описание приведено здесь зависимости от платформы

Ответ 3

это работает для меня

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

Ответ 4

Я создал небольшую библиотеку утилиты FileWatcher: https://github.com/finsterwalder/fileutils

Позволяет установить льготный период. Несколько событий внутри льготного периода накапливаются и запускаются только один раз.

Вы не должны использовать Notepad ++ для своих экспериментов, так как вы не знаете, что делает Notepad ++. Возможно, Notepad ++ на самом деле пишет файл несколько раз. Или он может написать файл с другим именем и переименовать его, когда это будет сделано или что-то еще. Создайте свой собственный код для управления файлами и посмотрите, что.