Когда я пытаюсь зарегистрировать файл вместо каталога java.nio.file.NotDirectoryException
брошен. Я могу прислушаться к единственному изменению файла, не целому каталогу?
Просто отфильтруйте события для файла, который Вы хотите в каталоге:
final Path path = FileSystems.getDefault().getPath(System.getProperty("user.home"), "Desktop");
System.out.println(path);
try (final WatchService watchService = FileSystems.getDefault().newWatchService()) {
final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
final WatchKey wk = watchService.take();
for (WatchEvent<?> event : wk.pollEvents()) {
//we only register "ENTRY_MODIFY" so the context is always a Path.
final Path changed = (Path) event.context();
System.out.println(changed);
if (changed.endsWith("myFile.txt")) {
System.out.println("My file has changed");
}
}
// reset the key
boolean valid = wk.reset();
if (!valid) {
System.out.println("Key has been unregisterede");
}
}
}
Здесь мы проверяем, является ли измененным файлом "myFile.txt", если это, затем делают что.
Нет не возможно зарегистрировать файл, сервис часов не прокладывает себе путь. Но регистрация каталог на самом деле часы изменения на детях каталога (файлы и подкаталоги), не изменения на самом каталоге.
, Если Вы хотите наблюдать файл, затем Вы регистрируете содержание каталога в сервисе часов. Path.register () в документации говорится:
WatchKey java.nio.file. Path.register (наблюдатель WatchService, события Kind [], Модификатор... модификаторы) IOException
бросков Регистрирует файл, расположенный этим путем с сервисом часов.
В этом выпуске, этот путь определяет местоположение каталога, который существует. каталог , зарегистрировался в сервисе часов так, чтобы за записями в каталоге можно было следить
Затем, необходимо обработать события на записях и обнаружить связанных с файлом, Вы интересуетесь путем проверки значения контекста события. Значение контекста представляет название записи (на самом деле путь записи относительно в путь ее родителя, который является точно дочерним именем). Вы имеете пример здесь .
Другие ответы являются правильными, что необходимо смотреть каталог и фильтр для конкретного файла. Однако Вы, вероятно, хотите поток, работающий в фоновом режиме. Принятый ответ может заблокироваться неограниченно долго на watchService.take();
и не закрывает WatchService. Решение, подходящее для отдельного потока, могло бы быть похожим:
public class FileWatcher extends Thread {
private final File file;
private AtomicBoolean stop = new AtomicBoolean(false);
public FileWatcher(File file) {
this.file = file;
}
public boolean isStopped() { return stop.get(); }
public void stopThread() { stop.set(true); }
public void doOnChange() {
// Do whatever action you want here
}
@Override
public void run() {
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
Path path = file.toPath().getParent();
path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
while (!isStopped()) {
WatchKey key;
try { key = watcher.poll(25, TimeUnit.MILLISECONDS); }
catch (InterruptedException e) { return; }
if (key == null) { Thread.yield(); continue; }
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
@SuppressWarnings("unchecked")
WatchEvent<Path> ev = (WatchEvent<Path>) event;
Path filename = ev.context();
if (kind == StandardWatchEventKinds.OVERFLOW) {
Thread.yield();
continue;
} else if (kind == java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY
&& filename.toString().equals(file.getName())) {
doOnChange();
}
boolean valid = key.reset();
if (!valid) { break; }
}
Thread.yield();
}
} catch (Throwable e) {
// Log or rethrow the error
}
}
}
я пытался работать из принятого ответа и эта статья . Необходимо смочь использовать этот поток с new FileWatcher(new File("/home/me/myfile")).start()
и остановить его путем вызова stopThread()
на потоке.
Apache предлагает класс FileWatchDog с doOnChange
метод.
private class SomeWatchFile extends FileWatchdog {
protected SomeWatchFile(String filename) {
super(filename);
}
@Override
protected void doOnChange() {
fileChanged= true;
}
}
И то, где когда-либо Вы хотите Вас, может запустить этот поток:
SomeWatchFile someWatchFile = new SomeWatchFile (path);
someWatchFile.start();
класс FileWatchDog опрашивает метку времени файла lastModified()
. Собственный WatchService от NIO Java более эффективен, так как оповещения являются немедленными.
Вы не можете наблюдать отдельный файл непосредственно, но можно отфильтровать то, в чем Вы не нуждаетесь.
Вот мой FileWatcher
реализация класса:
import java.io.File;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import static java.nio.file.StandardWatchEventKinds.*;
public abstract class FileWatcher
{
private Path folderPath;
private String watchFile;
public FileWatcher(String watchFile)
{
Path filePath = Paths.get(watchFile);
boolean isRegularFile = Files.isRegularFile(filePath);
if (!isRegularFile)
{
// Do not allow this to be a folder since we want to watch files
throw new IllegalArgumentException(watchFile + " is not a regular file");
}
// This is always a folder
folderPath = filePath.getParent();
// Keep this relative to the watched folder
this.watchFile = watchFile.replace(folderPath.toString() + File.separator, "");
}
public void watchFile() throws Exception
{
// We obtain the file system of the Path
FileSystem fileSystem = folderPath.getFileSystem();
// We create the new WatchService using the try-with-resources block
try (WatchService service = fileSystem.newWatchService())
{
// We watch for modification events
folderPath.register(service, ENTRY_MODIFY);
// Start the infinite polling loop
while (true)
{
// Wait for the next event
WatchKey watchKey = service.take();
for (WatchEvent<?> watchEvent : watchKey.pollEvents())
{
// Get the type of the event
Kind<?> kind = watchEvent.kind();
if (kind == ENTRY_MODIFY)
{
Path watchEventPath = (Path) watchEvent.context();
// Call this if the right file is involved
if (watchEventPath.toString().equals(watchFile))
{
onModified();
}
}
}
if (!watchKey.reset())
{
// Exit if no longer valid
break;
}
}
}
}
public abstract void onModified();
}
Для использования этого просто необходимо расширить и реализовать onModified()
метод как так:
import java.io.File;
public class MyFileWatcher extends FileWatcher
{
public MyFileWatcher(String watchFile)
{
super(watchFile);
}
@Override
public void onModified()
{
System.out.println("Modified!");
}
}
Наконец, начните наблюдать файл:
String watchFile = System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "Test.txt";
FileWatcher fileWatcher = new MyFileWatcher(watchFile);
fileWatcher.watchFile();
Я создал обертку вокруг Java 1.7's WatchService
, который позволяет регистрировать каталог и любое количество шарик шаблоны. Этот класс будет заботиться о фильтрации и только испускать события, которыми Вы интересуетесь.
try {
DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw
watchService.register( // May throw
new DirectoryWatchService.OnFileChangeListener() {
@Override
public void onFileCreate(String filePath) {
// File created
}
@Override
public void onFileModify(String filePath) {
// File modified
}
@Override
public void onFileDelete(String filePath) {
// File deleted
}
},
<directory>, // Directory to watch
<file-glob-pattern-1>, // E.g. "*.log"
<file-glob-pattern-2>, // E.g. "input-?.txt"
<file-glob-pattern-3>, // E.g. "config.ini"
... // As many patterns as you like
);
watchService.start(); // The actual watcher runs on a new thread
} catch (IOException e) {
LOGGER.error("Unable to register file change listener for " + fileName);
}
Полный код находится в этом repo.
Не уверенный в других, но я стону в объеме кода, должен был наблюдать единственный файл за изменениями с помощью основного WatchService API. Это должно быть более просто!
Вот несколько альтернатив, пользующихся сторонними библиотеками: