Wenn ich versuche, eine Datei anstelle eines Verzeichnisses zu registrieren, java.nio.file.NotDirectoryException
wird ausgelöst. Kann ich auf eine einzelne Dateiänderung warten, nicht auf das gesamte Verzeichnis?
java
watchservice
fedor.belov
quelle
quelle
Antworten:
Filtern Sie einfach die Ereignisse für die gewünschte Datei im Verzeichnis:
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"); } } }
Hier prüfen wir, ob die geänderte Datei "myFile.txt" ist, wenn es dann was auch immer ist.
quelle
OVERFLOW
. Sie müssen sich dafür nicht registrieren. Beispiel hier .Nein, es ist nicht möglich, eine Datei zu registrieren. Der Überwachungsdienst funktioniert auf diese Weise nicht. Beim Registrieren eines Verzeichnisses werden jedoch Änderungen an den untergeordneten Verzeichnissen (den Dateien und Unterverzeichnissen) und nicht an den Änderungen am Verzeichnis selbst überwacht.
Wenn Sie eine Datei ansehen möchten, registrieren Sie das enthaltene Verzeichnis beim Überwachungsdienst. Die Dokumentation zu Path.register () lautet:
Anschließend müssen Sie Ereignisse für Einträge verarbeiten und diejenigen identifizieren, die sich auf die Datei beziehen, an der Sie interessiert sind, indem Sie den Kontextwert des Ereignisses überprüfen. Der Kontextwert stellt den Namen des Eintrags dar (tatsächlich den Pfad des Eintrags relativ zum Pfad seines übergeordneten Eintrags, der genau der untergeordnete Name ist). Sie haben hier ein Beispiel .
quelle
Andere Antworten sind richtig, dass Sie ein Verzeichnis überwachen und nach Ihrer bestimmten Datei filtern müssen. Sie möchten jedoch wahrscheinlich, dass ein Thread im Hintergrund ausgeführt wird. Die akzeptierte Antwort kann auf unbestimmte Zeit blockiert werden
watchService.take();
und schließt den WatchService nicht. Eine Lösung, die für einen separaten Thread geeignet ist, könnte folgendermaßen aussehen: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 } } }
Ich habe versucht, anhand der akzeptierten Antwort und dieses Artikels zu arbeiten . Sie sollten in der Lage sein, diesen Thread mit zu verwenden
new FileWatcher(new File("/home/me/myfile")).start()
und ihn zu stoppen, indem SiestopThread()
den Thread aufrufen .quelle
setDaemon(boolean)
vorher auf,run()
je nachdem, wie sich Ihre App verhalten soll.Apache bietet eine FileWatchDog- Klasse mit einer
doOnChange
Methode an.private class SomeWatchFile extends FileWatchdog { protected SomeWatchFile(String filename) { super(filename); } @Override protected void doOnChange() { fileChanged= true; } }
Und wo immer Sie wollen, können Sie diesen Thread starten:
SomeWatchFile someWatchFile = new SomeWatchFile (path); someWatchFile.start();
Die FileWatchDog-Klasse fragt den
lastModified()
Zeitstempel einer Datei ab . Der native WatchService von Java NIO ist effizienter, da Benachrichtigungen sofort erfolgen.quelle
Sie können eine einzelne Datei nicht direkt ansehen, aber Sie können herausfiltern, was Sie nicht benötigen.
Hier ist meine
FileWatcher
Klassenimplementierung: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(); }
Um dies zu verwenden, müssen Sie die
onModified()
Methode nur folgendermaßen erweitern und implementieren :import java.io.File; public class MyFileWatcher extends FileWatcher { public MyFileWatcher(String watchFile) { super(watchFile); } @Override public void onModified() { System.out.println("Modified!"); } }
Beginnen Sie schließlich mit dem Betrachten der Datei:
String watchFile = System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "Test.txt"; FileWatcher fileWatcher = new MyFileWatcher(watchFile); fileWatcher.watchFile();
quelle
Ich bin mir bei anderen nicht sicher, aber ich stöhne über die Menge an Code, die erforderlich ist, um eine einzelne Datei mithilfe der grundlegenden WatchService-API auf Änderungen zu überwachen. Es muss einfacher sein!
Hier sind einige Alternativen, die Bibliotheken von Drittanbietern verwenden:
quelle
Ich habe einen Wrapper um Java 1.7 erstellt
WatchService
, mit dem ein Verzeichnis und eine beliebige Anzahl von Glob- Mustern registriert werden können. Diese Klasse kümmert sich um die Filterung und gibt nur Ereignisse aus, an denen Sie interessiert sind.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); }
Der vollständige Code befindet sich in diesem Repo .
quelle