É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.

cheng81
la source
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.

Rutesh Makhijani
la 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.

Stephen Denne
la source
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
@ArchimedesTrajano stackoverflow.com/questions/16251273/…
user1742529
39

J'utilise l'API VFS d'Apache Commons, voici un exemple de comment surveiller un fichier sans grand impact sur les performances:

DefaultFileMonitor

Telcontar
la source
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.

André
la source
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.

Christian
la source
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.

Tom Hawtin - Tacle
la source
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.

Mike Kramer
la source
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();
    }
}
Prasanna Sujeewa
la source
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.

jdh80
la source
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

onejigtwojig
la source
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();
}
BullyWiiPlaza
la source
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);
    }

  }
}
sjsperry
la source