Spec-Zone .ru
спецификации, руководства, описания, API
След: Существенные Классы
Урок: Основной ввод-вывод
Раздел: Файловый ввод-вывод (Обладающий NIO.2)
Наблюдение Каталога для Изменений
Домашняя страница > Существенные Классы > Основной ввод-вывод

Наблюдение Каталога для Изменений

Вы когда-либо редактировали файл, используя IDE или другого редактора, и диалоговое окно, кажется, сообщает Вам, что один из открытых файлов изменился на файловой системе и должен быть перезагружен? Или возможно, как IDE NetBeans, приложение только спокойно обновляет файл, не уведомляя Вас. Следующее демонстрационное диалоговое окно показывает, как это уведомление смотрит со свободным редактором, jEdit:

Выборка jEdit Диалоговое утверждение: следующие файлы были изменены на диске другой программой.

Диалоговое окно jEdit, Показывая, Что Обнаруживается Измененный Файл

Чтобы реализовать эту функциональность, названную уведомлением об изменении файла, программа должна быть в состоянии обнаружить то, что происходит с соответствующим каталогом на файловой системе. Один способ сделать так состоит в том, чтобы опросить файловую систему, ища изменения, но этот подход неэффективен. Это не масштабируется к приложениям, у которых есть сотни открытых файлов или каталогов, чтобы контролировать.

java.nio.file пакет обеспечивает API уведомления об изменении файла, названный API Службы Часов. Этот API позволяет Вам зарегистрировать каталог (или каталоги) со службой часов. Регистрируясь, Вы говорите службу, какими типами событий Вы интересуетесь: создание файла, удаление файла, или модификация файла. Когда служба обнаруживает мероприятие, она передается зарегистрированному процессу. У зарегистрированного процесса есть поток (или пул потоков) выделенный наблюдению за любыми событиями, для которых это зарегистрировалось. Когда событие входит, оно обрабатывается как необходимый.

Этот раздел покрывает следующее:

Наблюдайте Краткий обзор Службы

WatchService API является довольно низким уровнем, разрешая Вам настроить это. Можно использовать это как есть, или можно хотеть создавать высокоуровневый API сверху этого механизма так, чтобы это подошло для Ваших определенных потребностей.

Вот основные шаги, требуемые реализовывать службу часов:

WatchKeys ориентированы на многопотоковое исполнение и может использоваться с java.nio.concurrent пакет. Можно выделить пул потоков этому усилию.

Испытайте Это

Поскольку этот API более совершенствуется, испытайте его перед продолжением. Сохраните WatchDir пример к Вашему компьютеру, и компиляция это. Создайте a test каталог, который передадут к примеру. WatchDir использует единственный поток, чтобы обработать все события, таким образом, он блокирует ввод с клавиатуры, ожидая событий. Или выполните программу в отдельном окне, или в фоновом режиме, следующим образом:

java WatchDir test &

Игра с созданием, удалением, и редактированием файлов в test каталог. Когда любое из этих событий имеет место, сообщение печатается к консоли. Когда Вы закончили, удалите test каталог и WatchDir выходы. Или, если Вы предпочитаете, можно вручную уничтожить процесс.

Можно также наблюдать все дерево файла, определяя -r опция. Когда Вы определяете -r, WatchDir обходит дерево файла, регистрируя каждый каталог в службе часов.

Создание Службы Часов и Регистрация для Событий

Первый шаг должен создать новое WatchService при использовании newWatchService метод в FileSystem class, следующим образом:

WatchService watcher = FileSystems.getDefault().newWatchService();

Затем, зарегистрируйте один или более объектов в службе часов. Любой объект, который реализует Watchable интерфейс может быть зарегистрирован. Path class реализует Watchable интерфейс, таким образом, каждый каталог, который будет контролироваться, регистрируется как a Path объект.

Как с любым Watchable, Path class реализует два register методы. Эта страница использует версию с двумя параметрами, register(WatchService, WatchEvent.Kind<?>...). (Версия с тремя параметрами берет a WatchEvent.Modifier, который в настоящий момент не реализуется.)

Регистрируя объект в службе часов, Вы определяете типы событий, которых Вы хотите следить за развитием. Поддерживаемый StandardWatchEventKinds типы события следуют:

Следующий фрагмент кода показывает, как зарегистрировать a Path экземпляр для всех трех типов события:

import static java.nio.file.StandardWatchEventKinds.*;

Path dir = ...;
try {
    WatchKey key = dir.register(watcher,
                           ENTRY_CREATE,
                           ENTRY_DELETE,
                           ENTRY_MODIFY);
} catch (IOException x) {
    System.err.println(x);
}

Обработка Событий

Порядок событий в цикле обработки событий следует:

  1. Получите ключ часов. Обеспечиваются три метода:
    • poll – Возвращает ключ с очередями, при наличии. Возвраты сразу с a null значение, если недоступный.
    • poll(long, TimeUnit) – Возвращает ключ с очередями, если Вы доступны. Если ключ с очередями не сразу доступен, программа ожидает до требуемого времени. TimeUnit параметр определяет, является ли требуемое время наносекундами, миллисекундами, или некоторой другой единицей времени.
    • take – Возвращает ключ с очередями. Если никакой ключ с очередями не доступен, этот метод ожидает.
  2. Обработайте события на ожидании для ключа. Вы выбираете List из WatchEventsот pollEvents метод.
  3. Получите тип события при использовании kind метод. Независимо от того, что события ключ зарегистрировался для, возможно получить OVERFLOW событие. Можно хотеть обрабатывать переполнение или игнорировать его, но следует протестировать на него.
  4. Получите имя файла, связанное с событием. Имя файла сохранено как контекст события, таким образом, context метод используется, чтобы получить это.
  5. После того, как события для ключа были обработаны, Вы должны отложить ключ в a ready состояние, вызывая reset. Если этот метод возвращается false, ключ больше не действителен, и цикл может выйти. Этот шаг очень важен. Если Вы не в состоянии вызвать reset, этот ключ не будет получать дальнейшие события.

У ключа часов есть состояние. В любой момент времени его состояние могло бы быть одним из следующего:

Вот пример цикла обработки событий. Это берется от Email пример, который наблюдает каталог, ожидающий новых файлов, чтобы появиться. Когда новый файл становится доступным, он исследуется, чтобы определить, является ли это a text/plain файл при использовании probeContentType(Path) метод. Намерение - это text/plain файлы будут посланы по электронной почте к псевдониму, но ту деталь реализации оставляют читателю.

Методы, определенные для API службы часов, показывают полужирным:

for (;;) {

    // wait for key to be signaled
    WatchKey key;
    try {
        key = watcher.take();
    } catch (InterruptedException x) {
        return;
    }

    for (WatchEvent<?> event: key.pollEvents()) {
        WatchEvent.Kind<?> kind = event.kind();

        // This key is registered only
        // for ENTRY_CREATE events,
        // but an OVERFLOW event can
        // occur regardless if events
        // are lost or discarded.
        if (kind == OVERFLOW) {
            continue;
        }

        // The filename is the
        // context of the event.
        WatchEvent<Path> ev = (WatchEvent<Path>)event;
        Path filename = ev.context();

        // Verify that the new
        //  file is a text file.
        try {
            // Resolve the filename against the directory.
            // If the filename is "test" and the directory is "foo",
            // the resolved name is "test/foo".
            Path child = dir.resolve(filename);
            if (!Files.probeContentType(child).equals("text/plain")) {
                System.err.format("New file '%s'" +
                    " is not a plain text file.%n", filename);
                continue;
            }
        } catch (IOException x) {
            System.err.println(x);
            continue;
        }

        // Email the file to the
        //  specified email alias.
        System.out.format("Emailing file %s%n", filename);
        //Details left to reader....
    }

    // Reset the key -- this step is critical if you want to
    // receive further watch events.  If the key is no longer valid,
    // the directory is inaccessible so exit the loop.
    boolean valid = key.reset();
    if (!valid) {
        break;
    }
}

Получение Имени файла

Имя файла получается от контекста события. Email пример получает имя файла с этим кодом:

WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path filename = ev.context();

Когда Вы компилируете Email пример, это генерирует следующую ошибку:

Note: Email.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Эта ошибка является результатом строки кода, который бросает WatchEvent<T> к a WatchEvent<Path>. WatchDir пример избегает этой ошибки, создавая утилиту cast метод, который подавляет предупреждение непроверенное, следующим образом:

@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
    return (WatchEvent<Path>)event;
}

Если Вы незнакомы с @SuppressWarnings синтаксис, см. Аннотации.

Когда Использовать и Не Использовать Этот API

API Службы Часов разрабатывается для приложений, которые должны быть уведомлены о событиях изменения файла. Это хорошо подходит для любого приложения, как редактор или IDE, который потенциально имеет много открытых файлов и должен гарантировать, что файлы синхронизируются с файловой системой. Это также хорошо подходит для сервера приложений, который наблюдает каталог, возможно ожидающий .jsp или .jar файлы, чтобы отбросить, чтобы развернуть их.

Этот API не разрабатывается для того, чтобы индексировать жесткий диск. У большинства реализаций файловой системы есть собственная поддержка уведомления об изменении файла. API Службы Часов использует в своих интересах эту поддержку где доступный. Однако, когда файловая система не поддерживает этот механизм, Служба Часов опросит файловую систему, ожидающую событий.


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Обнаружение Файлов
Следующая страница: Другие Полезные Методы