Java WatchService не генерирует события во время просмотра подключенных дисков

Я реализовал средство просмотра файлов, но заметил, что средство просмотра файлов java nio не генерирует события для файлов, копируемых на подключенные диски. Например, я запустил средство просмотра файлов в Unix, чтобы посмотреть локальный каталог (/sharedfolder) который отображается на окнах (H:\), а затем я положил файл в этот каталог (H:\), но средство просмотра файлов не сгенерировало никакого события. Теперь, если я запускаю средство просмотра файлов в Windows, чтобы просмотреть подключенный диск (H:\) который ссылается на путь Unix (/sharedfolder) и из unix я помещаю файл в эту папку, наблюдатель файла идентифицирует изменение и генерирует событие. Похоже, ошибка, или, может быть, я что-то упускаю, какие-то мысли?

5 ответов

У меня та же проблема, когда я пытаюсь наблюдать за установленным общим ресурсом Windo ws через CIFS. Кажется, невозможно получить события файловой системы для монтирования CIFS.

Реализация linux Java 7 NIO FileWatcher использует inotify. Inotify - это подсистема ядра Linux, которая замечает изменения файловой системы, которая отлично работает для локальных каталогов, но, очевидно, не для монтирования CIFS.

В Oracle, кажется, не является высоким приоритетом исправление этой ошибки. (Это их ответственность? Больше проблем с ОС...)

JNotify также использует inotify в системах Linux, так что это тоже не вариант.

Таким образом, мониторинг подключенных дисков, к сожалению, ограничивается опросами:

  • Apache VFS DefaultFileMonitor для опроса каталогов (смонтированный общий ресурс)
  • File Poller основан на стандартном Java API.
  • Пользовательский File Poller с jCIFS (поэтому общий ресурс не нужно монтировать на хосте)

Я, наверное, попробую Apache VFS Monitor, потому что он обнаруживает создание, обновление и удаление файлов из коробки. Требуется смонтировать общий ресурс, но это дает ОС ответственность за соединения CIFS, а не мое приложение.

Функция просмотра файлов в JDK зависит от платформы, поскольку она использует собственные библиотеки, поэтому она может вести себя по-разному на разных платформах. Я удивлен, что это работает для сетевых дисков вообще - Windows должна опрашивать сетевые диски на предмет изменений, в то время как Linux этого не делает (по правде говоря, я должен сказать).

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

У меня такая же проблема. Я решил эту проблему, создав новый поток в основном классе и периодически касаясь файлов, чтобы запустить новое событие изменения.

Образец опроса dir каждые 10 секунд делает касание.

package com.ardevco.files;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;

public class Touch implements Runnable {

    private Path touchPath;

    public Touch(Path touchPath) {
        this.touchPath = touchPath;
        this.checkPath = checkPath;

    }

    public static void touch(Path file) throws IOException {
        long timestamp = System.currentTimeMillis();
        touch(file, timestamp);
    }

    public static void touch(Path file, long timestamp) throws IOException {
        if (Files.exists(file)) {
            FileTime ft = FileTime.fromMillis(timestamp);
            Files.setLastModifiedTime(file, ft);
        }
    }

    List<Path> listFiles(Path path) throws IOException {
        final List<Path> files = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
            for (Path entry : stream) {
                if (Files.isDirectory(entry)) {
                    files.addAll(listFiles(entry));
                }
                files.add(entry);
            }
        }
        return files;
    }

    @Override
    public void run() {
        while (true) {
            try {
                for (Path path : listFiles(touchPath)) {
                    touch(path);
                }
            } catch (IOException e) {
                System.out.println("Exception: " + e);
            }

            try {
                Thread.sleep(10000L);
            } catch (InterruptedException e) {
                System.out.println("Exception: " + e);
            }
        }

    }

}

У меня были похожие проблемы со скриптом Python, который просматривал содержимое файла журнала в удаленном каталоге Windows.

Вот мой ответ.

При подключении удаленного диска из Unix, в /etc/fstab использование //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

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

Команда может меняться в зависимости от версии Unix, это было протестировано в Debian. Это должно работать как задумано. Можете ли вы сказать мне, если это работает? Я планирую реализовать то же самое в Java, поэтому ответ может быть полезен и для меня.

Я тоже столкнулся с этим и пришел к тому же выводу, что и все остальные (CIFS + inotify = no go).

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

Сказав это, он работает, так что наслаждайтесь: http://github.com/rubyruy/watchntouch

Другие вопросы по тегам