Écoute de changement de fichier en Java


104

Je souhaite être averti lorsqu'un fichier a été modifié dans le système de fichiers. Je n'ai trouvé rien d'autre qu'un fil qui interroge la propriété lastModified File et clairement cette solution n'est pas optimale.


Merci pour toutes les réponses. Étant donné que mes besoins sont petits (je n'ai besoin que de recharger un fichier de propriétés modifié dans mon application Web ... principalement parce que le redémarrage de toute l'application Web est un peu lent), je vais rester fidèle au modèle de sondage. Au moins maintenant je sais qu'il n'y a pas de solution simple pour ces cas.
cheng81

14
Juste une note. Lorsque nous avons résolu ce problème avant, nous avons constaté que les fichiers volumineux avaient tendance à arriver lentement, et le mécanisme d'interrogation découvrait souvent un fichier nouveau ou modifié avant qu'il ne soit entièrement écrit. Pour résoudre ce problème, une solution «à deux bouchées» a été adoptée. L'interrogateur a remarqué qu'un fichier avait changé, mais n'a pas notifié au système un fichier nouveau / modifié jusqu'à ce qu'il ait l'air identique pour deux sondages: c'est-à-dire qu'il s'était stabilisé. Guéri de nombreuses erreurs de fichiers malveillants.
Steve Powell

1
En passant, Tomcat souffre de ce problème lors de la suppression de gros fichiers WAR dans le dossier webapps à partir de sources distantes et ce depuis longtemps.
John Rix

Réponses:


21

Au bas niveau, la seule façon de modéliser cet utilitaire est d'avoir un thread qui interroge un répertoire et surveille les attributs du fichier. Mais vous pouvez utiliser des modèles pour développer un adaptateur pour un tel utilitaire.

Par exemple, les serveurs d'applications j2ee comme Tomcat et d'autres ont une fonction de chargement automatique dans laquelle dès que le descripteur de déploiement change ou que la classe de servlet change, l'application redémarre.

Vous pouvez utiliser les bibliothèques de ces serveurs car la plupart du code de tomcat est réutilisable et open source.


59
Ce n'est plus le cas dans Java 7: il existe maintenant une API pour cela qui peut se connecter aux services de notification du système d'exploitation: blogs.oracle.com/thejavatutorials/entry/...
Arnout Engelen

Cette API est très inadéquate, elle ne fournit pas de notification pour les événements de fermeture de fichier sous Linux. Donc, dans un cas simple, lorsqu'un fichier est fermé, le copier dans un autre répertoire ne fonctionne pas.
binarytemple_picsolve

117

J'ai déjà écrit un moniteur de fichier journal et j'ai trouvé que l'impact sur les performances du système de l'interrogation des attributs d'un seul fichier, quelques fois par seconde, est en fait très faible.

Java 7, dans le cadre de NIO.2 a ajouté l' API WatchService

L'API WatchService est conçue pour les applications qui doivent être notifiées des événements de modification de fichier.


10
Je vois les exemples comme un répertoire de surveillance, mais qu'en est-il d'un fichier individuel?
Archimedes Trajano

@ArchimedesTrajano L'API vous avertit lorsqu'un fichier dans un répertoire a changé. L'événement déclenché inclut le nom du fichier qui a changé. Ainsi, vous pouvez gérer les événements d'un ou plusieurs fichiers et en ignorer d'autres.
Michael



27

Il existe une bibliothèque appelée jnotify qui encapsule inotify sur Linux et prend également en charge Windows. Je ne l'ai jamais utilisé et je ne sais pas à quel point c'est bon, mais ça vaut le coup d'essayer je dirais.


1
Cela fonctionne parfaitement et super simple à utiliser. J'utilise inotify depuis de nombreuses années. Il est rapide, stable et fiable
oᴉɹǝɥɔ

8

Java commons-io a un FileAlterationObserver . il interroge en combinaison avec un FileAlterationMonitor. Similaire au VFS commun. L'avantage est qu'il a beaucoup moins de dépendances.

edit: Moins de dépendances n'est pas vrai, elles sont facultatives pour VFS. Mais il utilise un fichier java au lieu de la couche d'abstraction VFS.


4

«Plus de fonctionnalités NIO» a une fonctionnalité de surveillance des fichiers, avec une implémentation dépendante du système d'exploitation sous-jacent. Doit être dans JDK7.


Pourriez-vous être plus précis ou publier un lien vers la documentation? Je ne trouve rien à ce sujet ...
Luciano

Cela semble être le paquet java.nio.file. Voir un tutoriel .
David L.

4

J'exécute cet extrait de code chaque fois que je vais lire le fichier de propriétés, ne lisant réellement le fichier que s'il a été modifié depuis la dernière fois que je l'ai lu. J'espère que cela aide quelqu'un.

private long timeStamp;
private File file;

private boolean isFileUpdated( File file ) {
  this.file = file;
  this.timeStamp = file.lastModified();

  if( this.timeStamp != timeStamp ) {
    this.timeStamp = timeStamp;
    //Yes, file is updated
    return true;
  }
  //No, file is not updated
  return false;
}

Une approche similaire est utilisée dans Log4J FileWatchdog.


2

Vous pouvez écouter les modifications de fichiers à l'aide d'un FileReader. Plz voir l'exemple ci-dessous

// File content change listener 
private String fname;
private Object lck = new Object();
... 
public void run()
{
    try
    {
        BufferedReader br = new BufferedReader( new FileReader( fname ) );
        String s;
        StringBuilder buf = new StringBuilder();
        while( true )
        {
            s = br.readLine();
            if( s == null )
            {
                synchronized( lck )
                {
                    lck.wait( 500 );
                }
            }
            else
            {
               System.out.println( "s = " + s );
            }

        }
    }
    catch( Exception e )
    {
        e.printStackTrace();
    }
}

2

Si vous êtes prêt à vous séparer d'un peu d'argent, JNIWrapper est une bibliothèque utile avec un Winpack, vous pourrez obtenir des événements du système de fichiers sur certains fichiers. Malheureusement Windows uniquement.

Voir https://www.teamdev.com/jniwrapper .

Sinon, le recours au code natif n'est pas toujours une mauvaise chose surtout quand le meilleur proposé est un mécanisme d'interrogation par rapport à un événement natif.

J'ai remarqué que les opérations du système de fichiers Java peuvent être lentes sur certains ordinateurs et peuvent facilement affecter les performances de l'application si elles ne sont pas bien gérées.


1

Vous pouvez également envisager la JCI Apache Commons (Java Compiler Interface). Bien que cette API semble être axée sur la compilation dynamique de classes, elle inclut également des classes dans son API qui surveille les modifications de fichiers.

Exemple: http://commons.apache.org/jci/usage.html




1

L'interrogation de la dernière propriété de fichier modifiée est cependant une solution simple mais efficace. Définissez simplement une classe étendant my FileChangedWatcheret implémentez la onModified()méthode:

import java.io.File;

public abstract class FileChangedWatcher
{
    private File file;

    public FileChangedWatcher(String filePath)
    {
        file = new File(filePath);
    }

    public void watch() throws InterruptedException
    {
        long currentModifiedDate = file.lastModified();

        while (true)
        {
            long newModifiedDate = file.lastModified();

            if (newModifiedDate != currentModifiedDate)
            {
                currentModifiedDate = newModifiedDate;
                onModified();
            }

            Thread.sleep(100);
        }
    }

    public String getFilePath()
    {
        return file.getAbsolutePath();
    }

    protected abstract void onModified();
}

0

Semblable aux autres réponses, voici comment je l'ai fait en utilisant File, Timer et TimerTask pour laisser cela fonctionner en tant qu'interrogation de thread d'arrière-plan à des intervalles définis.

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

public class FileModifiedWatcher
{
  private static File file;
  private static int pollingInterval;
  private static Timer fileWatcher;
  private static long lastReadTimeStamp = 0L;

  public static boolean init(String _file, int _pollingInterval)
  {
    file =  new File(_file);
    pollingInterval = _pollingInterval; // In seconds

    watchFile();

    return true;
  }

  private static void watchFile()
  {
    if ( null == fileWatcher )
    {
      System.out.println("START");

      fileWatcher = new Timer();

      fileWatcher.scheduleAtFixedRate(new TimerTask()
      {
        @Override
        public void run()
        {

          if ( file.lastModified() > lastReadTimeStamp )
          {
            System.out.println("File Modified");
          }

          lastReadTimeStamp = System.currentTimeMillis();
        }
      }, 0, 1000 * pollingInterval);
    }

  }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.