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