web-dev-qa-db-ger.com

Java WatchService generiert keine Ereignisse, während zugeordnete Laufwerke überwacht werden

Ich habe einen Datei-Watcher implementiert, aber festgestellt, dass der Java nio-Datei-Watcher keine Ereignisse für Dateien generiert, die auf zugeordnete Laufwerke kopiert werden. Beispielsweise habe ich den Datei-Watcher unter Unix ausgeführt, um ein lokales Verzeichnis (/sharedfolder) zu überwachen, das unter Windows (H:\) zugeordnet ist, und dann habe ich eine Datei in dieses Verzeichnis (H:\) gestellt, der Datei-Watcher jedoch nicht irgendein Ereignis erzeugt. Wenn ich nun die Dateiüberwachung unter Windows ausführe, um das zugeordnete Laufwerk (H:\) zu überwachen, das auf einen Unix-Pfad (/sharedfolder) verweist, und unter Unix eine Datei in diesen Ordner lege, erkennt die Dateiüberwachung die Änderung und generiert ein Ereignis. Es sieht aus wie ein Käfer, oder vermisse ich vielleicht etwas, irgendwelche Gedanken?

24
Ramcis

Ich habe das gleiche Problem beim Versuch, eine aktivierte Windows-Freigabe über CIFS zu überwachen. Es scheint nicht möglich zu sein, Dateisystemereignisse für CIFS-Bereitstellungen abzurufen .

Die Linux-Implementierung von Java 7 NIO FileWatcher verwendet inotify . Inotify ist ein Linux-Kernel-Subsystem, mit dem Änderungen am Dateisystem festgestellt werden. Dies funktioniert perfekt für lokale Verzeichnisse, anscheinend jedoch nicht für CIFS-Bereitstellungen .

Bei Oracle scheint es keine hohe Priorität zu haben, diesen Fehler zu beheben. (Ist es ihre Verantwortung? Eher ein OS-Problem ...)

JNotify verwendet auch inotify auf Linux-Systemen, daher ist dies auch keine Option.

Die Überwachung zugeordneter Laufwerke scheint daher leider auf Pollers beschränkt zu sein:

  • Apache VFS DefaultFileMonitor um Verzeichnisse abzufragen (gemountete Freigabe)
  • File Poller basierend auf der Standard Java API.
  • Benutzerdefinierter Datei-Poller mit jCIFS (damit die Freigabe nicht auf dem Host bereitgestellt werden muss)

Ich werde es wahrscheinlich mit dem Apache VFS-Monitor versuchen, da er das Erstellen, Aktualisieren und Löschen von Dateien sofort erkennt. Es ist erforderlich, die Freigabe bereitzustellen, dies gibt dem Betriebssystem jedoch die Verantwortung für CIFS-Verbindungen und nicht für meine Anwendung.

24
Tim Van Laer

Die Dateiüberwachungsfunktion in JDK ist plattformabhängig, da native Bibliotheken verwendet werden und sich daher auf verschiedenen Plattformen unterschiedlich verhalten können. Ich bin überrascht, dass es für Netzwerklaufwerke überhaupt funktioniert - Windows muss Netzwerklaufwerke auf Änderungen abfragen, Linux nicht (zu Recht, sollte ich sagen).

In der Regel ist diese Art der Überwachung im Betriebssystemkern implementiert, der natürlich weiß, welche Dateien lokal geändert/erstellt/usw. werden. Es gibt jedoch keine einfachen Möglichkeiten für das Betriebssystem, um zu wissen, was auf dem Netzlaufwerk geschieht, da es keine ausschließliche Kontrolle darüber hat.

4
maximdim

Ich hatte das gleiche problem Ich habe es gelöst, indem ich einen neuen Thread in der Hauptklasse erstellt und die Dateien regelmäßig berührt habe, damit ein neues Änderungsereignis ausgelöst wird.

Das Beispiel fragt alle 10 Sekunden das Verzeichnis ab und führt eine Berührung durch.

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);
            }
        }

    }

}
2
Mehmet Erdemsoy

Auch ich bin darauf gestoßen und bin zu dem gleichen Schluss gekommen wie alle anderen hier (CIFS + inotify = no go).

Da mein Workflow jedoch sowohl von Remote-Bereitstellungen als auch von Tools zur automatischen Kompilierung abhängt, die auf inotify basieren, habe ich eine (ziemlich verzweifelte und hackige) Lösung erstellt, die im Grunde nur Polling verwendet, um nach Änderungen zu suchen und dann dieselben Dateien erneut zu berühren auf der montierten Seite, diezu zünden scheint, um Ereignisse zu benachrichtigen. Es ist nicht mein stolzester Moment.

Trotzdem funktioniert es, also viel Spaß: http://github.com/rubyruy/watchntouch

1
rubyruy

Ich hatte ähnliche Probleme mit einem Python-Skript, das den Inhalt einer Protokolldatei in einem Remote-Windows-Verzeichnis überwachte.

Hier ist meine Antwort.

Verwenden Sie beim Zuordnen des Remote-Laufwerks vom Unix aus im /etc/fstab den //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

Sie können eine Anmeldeinformationsdatei verwenden, um zu vermeiden, dass das Kennwort im Nur-Text-Format vorliegt.

Der Befehl kann sich je nach Unix-Version ändern, dies wurde unter Debian getestet. Es sollte wie vorgesehen funktionieren. Kannst du mir sagen, ob es funktioniert? Ich plane, dasselbe in Java zu implementieren, sodass die Antwort auch für mich nützlich sein könnte.

1
1337Wolf