Implémentation Java IO de unix / linux «tail -f»

Je me demande quelles techniques et / ou bibliothèques utiliser pour implémenter les fonctionnalités de la commande linux “tail -f”. Je cherche essentiellement une extension / remplacement de java.io.FileReader . Le code client pourrait ressembler à ceci:

 TailFileReader lft = new TailFileReader("application.log"); BufferedReader br = new BufferedReader(lft); Ssortingng line; try { while (true) { line= br.readLine(); // do something interesting with line } } catch (IOException e) { // barf } 

La pièce manquante est une implémentation raisonnable de TailFileReader . Il devrait pouvoir lire des parties du fichier qui existent avant que le fichier ne soit ouvert, ainsi que les lignes ajoutées.

    La possibilité de continuer à lire un fichier et d’attendre que le fichier contienne d’autres mises à jour ne devrait pas être si difficile à réaliser dans le code vous-même. Voici un pseudo-code:

     BufferedReader br = new BufferedReader(...); Ssortingng line; while (keepReading) { line = reader.readLine(); if (line == null) { //wait until there is more of the file for us to read Thread.sleep(1000); } else { //do something interesting with the line } } 

    Je suppose que vous souhaitez placer ce type de fonctionnalité dans son propre thread, de manière à pouvoir le mettre en veille et à ne pas affecter les autres domaines de votre application. Vous souhaitez exposer keepReading dans un setter afin que votre classe principale ou d’autres parties de l’application puissent fermer le thread en toute sécurité sans aucun autre casse-tête, simplement en appelant stopReading() ou quelque chose de similaire.

    Jetez un coup d’oeil à l’implémentation Apache Commons de la classe Tailer . Il semble également gérer la rotation des journaux.

    Vérifiez JLogTailer , qui fait cette logique.

    Le point principal du code est:

     public void run() { try { while (_running) { Thread.sleep(_updateInterval); long len = _file.length(); if (len < _filePointer) { // Log must have been jibbled or deleted. this.appendMessage("Log file was reset. Restarting logging from start of file."); _filePointer = len; } else if (len > _filePointer) { // File must have had something added to it! RandomAccessFile raf = new RandomAccessFile(_file, "r"); raf.seek(_filePointer); Ssortingng line = null; while ((line = raf.readLine()) != null) { this.appendLine(line); } _filePointer = raf.getFilePointer(); raf.close(); } } } catch (Exception e) { this.appendMessage("Fatal error reading log file, log tailing has stopped."); } // dispose(); } 

    Il y a quelque temps, j’ai mis au point une courte implémentation de “tail -f” dans Scala: tailf . Il s’occupe également de la rotation des fichiers et vous pouvez définir votre propre logique lorsque vous atteignez EOF ou que le fichier a été renommé.

    Vous pouvez jeter un coup d’oeil et le porter sur Java, car il n’y a rien de complexe ici. Quelques notes: le fichier principal est Tail.scala et il définit fondamentalement le FollowInputStream , qui prend en charge la méthode EOF / rename et follow , qui encapsule la FollowInputStream dans une énumération non limitée dans SequenceInputStream . Ainsi, dès que FollowingInputStream FollowInputStream, SequenceInputStream demande l’élément suivant à partir d’une Enumeration et qu’un autre groupe FollowingInputStream est créé.

    Je suis tombé récemment sur rxjava-file , c’est une extension de RxJava . Contrairement aux autres solutions, il utilise le NIO de Java.

     import rx.Observable; import rx.functions.Action1; import com.github.davidmoten.rx.FileObservable; // ... class definition omitted public void tailLogFile() throws InterruptedException { Observable tailer = FileObservable.tailer() .file("application.log") // absolute path .tailText(); tailer.subscribe( new Action1() { @Override public void call(Ssortingng line) { System.out.println("you got line: " + line); } }, new Action1() { @Override public void call(Throwable e) { System.out.println("you got error: " + e); e.printStackTrace(); } } ); // this solution operates threaded, so something // is required that prevents premature termination Thread.sleep(120000); } 

    Voici une petite histoire que vous pouvez utiliser comme pointeur:

    J’ai codé TailingInputStream au travail pour la même raison. Il utilise essentiellement File et rafraîchi son contenu à la demande et vérifié avec le tampon interne s’il a changé de manière significative (tampon mémoire de 2 Ko IIRC), puis fait ce que fait le tail -f. Un peu piraté, oui, mais cela fonctionne parfaitement et ne gâche pas les threads ou quelque chose de ce genre – il est compatible avec la version 1.4.2 au moins.

    Cela dit, il était beaucoup plus facile à faire que ReverseInputStream qui allait du début au début et ne mourrait pas si le fichier était mis à jour à la volée …

    Si votre code ne doit être exécuté que sur des systèmes Unix, vous pourrez peut-être vous contenter d’exposer et d’appeler directement tail -f .

    Comme alternative plus impliquée, vous pouvez jeter un coup d’œil à l’implémentation de GNU tail et le transférer sur Java. (Je ne suis pas sûr si cela ne ferait pas déjà de votre code un travail dérivé.)

    Juste a été confronté au même problème – a trouvé la “plus simple” implémentation ici: Java Tail .

    * Super substance * – prêt pour la production;)

    J’espère que la citation de code ne laissera pas tomber une licence.

      import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Java implementation of the Unix tail command * * @param args[0] File name * @param args[1] Update time (seconds). Optional. Default value is 1 second * * @author Luigi Viggiano (original author) http://it.newinstance.it/2005/11/19/listening-changes-on-a-text-file-unix-tail-implementation-with-java/ * @author Alessandro Melandri (modified by) * */ public class Tail { static long sleepTime = 1000; public static void main(Ssortingng[] args) throws IOException { if (args.length > 0){ if (args.length > 1) sleepTime = Long.parseLong(args[1]) * 1000; BufferedReader input = new BufferedReader(new FileReader(args[0])); Ssortingng currentLine = null; while (true) { if ((currentLine = input.readLine()) != null) { System.out.println(currentLine); continue; } try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } input.close(); } else { System.out.println("Missing parameter!\nUsage: java JavaTail fileName [updateTime (Seconds. default to 1 second)]"); } } } 

    J’ai trouvé cette belle implémentation de queue.

    Auteur: amelandri

    Souce de: https://gist.github.com/amelandri/1376896

     import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; /** * Java implementation of the Unix tail command * * @param args[0] File name * @param args[1] Update time (seconds). Optional. Default value is 1 second * * @author Luigi Viggiano (original author) http://it.newinstance.it/2005/11/19/listening-changes-on-a-text-file-unix-tail-implementation-with-java/ * @author Alessandro Melandri (modified by) * */ public class Tail { static long sleepTime = 1000; public static void main(Ssortingng[] args) throws IOException { if (args.length > 0){ if (args.length > 1) sleepTime = Long.parseLong(args[1]) * 1000; BufferedReader input = new BufferedReader(new FileReader(args[0])); Ssortingng currentLine = null; while (true) { if ((currentLine = input.readLine()) != null) { System.out.println(currentLine); continue; } try { Thread.sleep(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } input.close(); } else { System.out.println("Missing parameter!\nUsage: java JavaTail fileName [updateTime (Seconds. default to 1 second)]"); } } }