En Java, quel est le meilleur / modèle le plus sûr pour la surveillance d'un fichier en cours ajouté à?

StackOverflow https://stackoverflow.com/questions/1073274

  •  21-08-2019
  •  | 
  •  

Question

Le processus de quelqu'un d'autre crée un fichier CSV en ajoutant un ligne à la fois pour, comme les événements se produisent. Je n'ai aucun contrôle sur le format de fichier ou l'autre processus, mais je sais que ce n'append.

Dans un programme Java, je voudrais suivre ce dossier, et quand une ligne est ajoutée lire la nouvelle ligne et de réagir en fonction du contenu. Ignorer le problème de l'analyse syntaxique CSV pour l'instant. Quelle est la meilleure façon de suivre le dossier des changements et lire une ligne à la fois?

Idéalement, cela utilisera les classes de la bibliothèque standard. Le fichier peut bien être sur un lecteur réseau, donc je voudrais quelque chose robuste à l'échec. Je préfère ne pas utiliser la relève si possible -. Je préfère une sorte de bloquer la place solution

Modifier - étant donné qu'une solution de blocage est impossible avec des classes standard (merci pour cette réponse), quelle est la solution la plus robuste de vote? Je préfère ne pas relire le fichier entier à chaque fois qu'il pourrait se développer assez grand.

Était-ce utile?

La solution

Depuis Java 7, il a été le newWatchService () méthode sur le classe FileSystem .

Cependant, il y a des mises en garde:

  • Il est seulement Java 7
  • Il est une méthode facultative
  • il regarde uniquement les répertoires, vous devez donc faire le fichier vous-même la manipulation, et l'inquiétude sur le fichier en mouvement etc

Avant Java 7, il est impossible avec les API standard.

J'ai essayé les éléments suivants (vote sur un intervalle de 1 sec) et il fonctionne (écrit seulement dans le traitement):

  private static void monitorFile(File file) throws IOException {
    final int POLL_INTERVAL = 1000;
    FileReader reader = new FileReader(file);
    BufferedReader buffered = new BufferedReader(reader);
    try {
      while(true) {
        String line = buffered.readLine();
        if(line == null) {
          // end of file, start polling
          Thread.sleep(POLL_INTERVAL);
        } else {
          System.out.println(line);
        }
      }
    } catch(InterruptedException ex) {
     ex.printStackTrace();
    }
  }

Comme personne d'autre a suggéré une solution qui utilise une production actuelle de Java je pensais que je l'ajoute. S'il y a des défauts s'il vous plaît ajouter dans les commentaires.

Autres conseils

Vous pouvez vous inscrire pour être averti par le système de fichiers en cas de changement se produit dans le fichier en utilisant la classe WatchService. Cela nécessite java7, voici le lien pour la documentation http://docs.oracle .com / JavaSE / tutorial / eSSENTIEL / io / notification.html

ici le fragment de code pour le faire:

public FileWatcher(Path dir) {
   this.watcher = FileSystems.getDefault().newWatchService();
   WatchKey key = dir.register(watcher, ENTRY_MODIFY);
}

void processEvents() {
    for (;;) {
        // wait for key to be signalled
        WatchKey key;
        try {
            key = watcher.take();
        } catch (InterruptedException x) {
            return;
        }

        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent.Kind<?> kind = event.kind();

            if (kind == OVERFLOW) {
                continue;
            }
            // Context for directory entry event is the file name of entry
            WatchEvent<Path> ev = cast(event);
            Path name = ev.context();
            Path child = dir.resolve(name);
            // print out event
            System.out.format("%s: %s file \n", event.kind().name(), child);
        }
        // reset key and remove from set if directory no longer accessible
        boolean valid = key.reset();
    }
}

Utilisation de Java 7 WatchService , une partie de NIO.2

  

L'API WatchService est conçu pour les applications qui ont besoin d'être informé sur les événements de modification de fichier.

Ceci est impossible avec les classes de la bibliothèque standard. Voir cette question pour plus de détails.

Pour polling efficace, il sera préférable d'utiliser Random Access . Cela vous aidera si vous vous souvenez de la position de la dernière fin de fichier et de commencer la lecture à partir de là.

Juste pour développer la dernière entrée de Nick Fortescue, voici deux classes que vous pouvez exécuter simultanément (par exemple dans deux fenêtres shell différentes) qui montre qu'un fichier donné peut simultanément être écrit par un processus et lu par un autre.

Ici, les deux processus exécuteront ces classes Java, mais je suppose que le processus d'écriture pourrait être de toute autre application. (En supposant qu'il ne détient pas un verrou exclusif sur le fichier-là sont les verrous du système de fichiers sur certains systèmes d'exploitation?)

Je l'ai testé avec succès ces deux classes sur les deux Windoze et Linux. Je voudrais bien savoir s'il y a une condition (par exemple le système d'exploitation) sur lequel ils échouent.

Classe 1:

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;

public class FileAppender {

    public static void main(String[] args) throws Exception {
        if ((args != null) && (args.length != 0)) throw
            new IllegalArgumentException("args is not null and is not empty");

        File file = new File("./file.txt");
        int numLines = 1000;
        writeLines(file, numLines);
    }

    private static void writeLines(File file, int numLines) throws Exception {
        PrintWriter pw = null;
        try {
            pw = new PrintWriter( new FileWriter(file), true );
            for (int i = 0; i < numLines; i++) {
                System.out.println("writing line number " + i);
                pw.println("line number " + i);
                Thread.sleep(100);
            }
        }
        finally {
            if (pw != null) pw.close();
        }
    }

}

Classe 2:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

public class FileMonitor {

    public static void main(String[] args) throws Exception {
        if ((args != null) && (args.length != 0)) throw
            new IllegalArgumentException("args is not null and is not empty");

        File file = new File("./file.txt");
        readLines(file);
    }

    private static void readLines(File file) throws Exception {
        BufferedReader br = null;
        try {
            br = new BufferedReader( new FileReader(file) );
            while (true) {
                String line = br.readLine();
                if (line == null) { // end of file, start polling
                    System.out.println("no file data available; sleeping..");
                    Thread.sleep(2 * 1000);
                }
                else {
                    System.out.println(line);
                }
            }
        }
        finally {
            if (br != null) br.close();
        }
    }

}

Malheureusement, la classe TailInputStream, qui peut être utilisé pour surveiller la fin d'un fichier, n'est pas une des classes de la plate-forme Java standard, mais il y a quelques implémentations sur le web. Vous pouvez trouver une implémentation de classe TailInputStream ainsi qu'un exemple d'utilisation sur http://www.greentelligent.com/java / tailinputstream .

Poll, soit sur un cycle cohérent ou sur un cycle aléatoire; 200-2000ms devrait être un bon sondage aléatoire durée d'intervalle.

Vérifier deux choses ...

Si vous devez surveiller la croissance de fichier, puis vérifier le nombre EOF / octet, et assurez-vous de les comparer et les temps fileaccess ou FILEWRITE avec le sondage lass. Si (>), le fichier a été écrit.

Alors, moissonneuse-batteuse avec la vérification de verrou exclusif / accès en lecture. Si le fichier peut être verrouillé en lecture et il a grandi, puis tout ce qui était écrit qu'il a terminé.

Vérification de la propriété soit seul, vous obtiendrez pas nécessairement un état de garantie écrite ++ et réellement fait et disponible.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top