web-dev-qa-db-fra.com

Java WatchService ne générant pas d'événements tout en regardant des lecteurs mappés

J'ai implémenté un observateur de fichiers, mais j'ai remarqué que l'observateur de fichiers Java nio ne générait pas d'événements pour les fichiers copiés sur des lecteurs mappés. Par exemple, j'ai exécuté l'observateur de fichiers sous Unix pour regarder un répertoire local (/sharedfolder) mappé sous Windows (H:\), puis j'ai placé un fichier dans ce répertoire (H:\), mais l'observateur de fichiers ne l'a pas encore. généré un événement. Maintenant, si j'exécute l'observateur de fichiers sous Windows pour surveiller le lecteur mappé (H:\) qui fait référence à un chemin d'accès unix (/sharedfolder) et que depuis unix, je mets un fichier dans ce dossier, l'observateur identifie le changement et génère un événement. Cela ressemble à un insecte, ou peut-être que je manque quelque chose, des pensées?

24
Ramcis

J'ai le même problème en essayant de regarder un partage de fenêtres montées via CIFS. Il ne semble pas possible d’obtenir événements du système de fichiers pour les montages CIFS .

L’implémentation sous Linux de NIO Java 7 FileWatcher utilise inotify . Inotify est un sous-système du noyau Linux permettant de remarquer les modifications du système de fichiers, ce qui convient parfaitement aux répertoires locaux, mais apparemment pas à montages CIFS .

Chez Oracle, il ne semble pas prioritaire de corriger ce bogue . (Est-ce leur responsabilité? Plus d'un problème de système d'exploitation ...)

JNotify utilise également inotify sur les systèmes linux, il ne s'agit donc pas d'une option.

La surveillance des lecteurs ainsi cartographiés semble malheureusement se limiter aux enquêteurs:

  • Apache VFS DefaultFileMonitor pour interroger les répertoires (partage monté)
  • Fichier Poller basé sur l'API Java standard.
  • Fichier personnalisé Poller avec jCIFS _ (le partage n'a donc pas besoin d'être monté sur l'hôte)

Je vais probablement essayer le moniteur Apache VFS, car il détecte la création de fichier, les mises à jour et les suppressions immédiatement. Cela nécessite de monter le partage, mais cela confère au système d'exploitation la responsabilité des connexions CIFS et non de mon application.

24
Tim Van Laer

La fonctionnalité de visionnage de fichiers dans JDK dépend de la plate-forme, car elle utilise des bibliothèques natives, de sorte qu'elle peut se comporter différemment d'une plate-forme à l'autre. Je suis surpris que cela fonctionne pour tous les lecteurs réseau - Windows doit interroger les lecteurs mappés sur le réseau pour connaître les modifications, contrairement à Linux (à juste titre, devrais-je dire).

Habituellement, ce type de surveillance est implémenté dans le noyau du système d’exploitation, qui sait évidemment quels fichiers sont modifiés/créés/etc. localement, mais il n’existe pas de moyen facile pour le système d’exploitation de savoir ce qui se passe sur le lecteur réseau car il n’exerce pas un contrôle exclusif sur ce dernier.

4
maximdim

J'ai eu le même problème. Je l'ai résolu en créant un nouveau fil dans la classe principale et en touchant les fichiers périodiquement afin qu'un nouvel événement de modification soit déclenché.

L'échantillon interroge le répertoire toutes les 10 secondes.

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

Moi aussi, je me suis heurté à cela et je suis arrivé à la même conclusion que tout le monde ici (CIFS + inotify = no go).

Cependant, comme mon flux de travail dépendait à la fois de montages distants et d'outils de compilation automatique reposant sur inotify, j'ai finalement créé une solution (plutôt désespérée) qui n'utilise que la scrutation pour surveiller les modifications, puis retouche les mêmes fichiers sur le côté monté, ce que fait semble déclencher des événements inotify. Ce n'est pas mon moment le plus fier.

Cela dit, cela fonctionne, alors profitez de: http://github.com/rubyruy/watchntouch

1
rubyruy

J'ai eu des problèmes similaires avec un script Python regardant le contenu d'un fichier journal sur un répertoire Windows distant.

Voici ma réponse.

Lors du mappage du lecteur distant sous Unix, dans /etc/fstab, utilisez //xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

Vous pouvez utiliser un fichier d'informations d'identification pour éviter d'avoir le mot de passe en texte brut.

La commande peut changer en fonction de la version unix, ceci a été testé sous debian. Cela devrait fonctionner comme prévu. Pouvez-vous me dire si cela fonctionne? Je prévois d’implémenter les mêmes éléments en Java afin que la réponse me soit également utile.

1
1337Wolf