wake-up-neo.net

Java IO Implementierung von Unix/Linux "tail -f"

Ich frage mich, mit welchen Techniken und/oder Bibliotheken die Funktionalität des Linux-Befehls "tail -f" implementiert werden soll. Ich suche im Wesentlichen nach einem Tropfen Add-On/Ersatz für Java.io.FileReader. Der Client-Code könnte ungefähr so ​​aussehen:

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

Das fehlende Stück ist eine sinnvolle Implementierung von TailFileReader. Es sollte in der Lage sein, vor dem Öffnen der Datei vorhandene Teile der Datei sowie die hinzugefügten Zeilen zu lesen. 

64
Gary

Die Möglichkeit, eine Datei weiter zu lesen und zu warten, bis in der Datei weitere Updates für Sie vorhanden sind, sollte im Code selbst nicht so schwer sein. Hier ist ein Pseudo-Code:

BufferedReader br = new BufferedReader(...);
String 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
    }
}

Ich würde davon ausgehen, dass Sie diese Art von Funktionalität in einen eigenen Thread einbinden möchten, damit Sie sie schlafen können und keine anderen Bereiche Ihrer Anwendung betreffen. Sie möchten keepReading in einem Setter freigeben, damit Ihre Hauptklasse/andere Teile der Anwendung den Thread ohne weitere Kopfschmerzen sicher beenden können, indem Sie einfach stopReading() oder etwas Ähnliches aufrufen.

33
matt b

Schauen Sie sich die Apache Commons-Implementierung von Tailer class an. Es scheint auch die Protokollrotation zu bewältigen.

55
Chetan Sastry

Überprüfen Sie JLogTailer , wodurch diese Logik ausgeführt wird.

Der Hauptpunkt im Code ist:

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);
                String 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();
}
12
aldrinleal

Ich habe vor einiger Zeit eine kurze Implementierung von "tail -f" in Scala erstellt: tailf . Es kümmert sich auch um die Dateirotation, und Sie können Ihre eigene Logik definieren, was zu tun ist, wenn EOF erreicht wird oder die Datei umbenannt wurde.

Sie können einen Blick darauf werfen und es nach Java portieren, da dort eigentlich nichts komplexes ist. Einige Anmerkungen: Die Hauptdatei ist Tail.scala und im Grunde definiert sie FollowingInputStream , die sich um EOF/Rename und follow Methode kümmert, wodurch FollowingInputStream in SequenceInputStream in eine unbegrenzte Aufzählung eingeschlossen wird. Sobald also FollowingInputStream beendet ist, fordert SequenceInputStream das nächste Element von einer Enumeration an, und eine andere FollowingInputStream wird erstellt.

8

Ich bin vor kurzem über rxjava-file gestolpert. Es ist eine Erweiterung von RxJava . Im Gegensatz zu den anderen Lösungen wird Java von NIO verwendet. 

import rx.Observable;
import rx.functions.Action1;
import com.github.davidmoten.rx.FileObservable;

// ... class definition omitted

public void tailLogFile() throws InterruptedException {
    Observable<String> tailer = FileObservable.tailer()
                                .file("application.log") // absolute path
                                .tailText();

    tailer.subscribe(
        new Action1<String>() {
            @Override
            public void call(String line) {
                System.out.println("you got line: " + line);
            }
        },
        new Action1<Throwable>() {
            @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);
}
3
cheffe

Ich habe diese Nice-Tail-Implementierung gefunden.

Urheber: amelandri 

Souce von: 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(String[] 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]));
      String 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)]");
        }
      }

}
0
Mahesh K

Wenn Ihr Code nur auf Unix-Systemen ausgeführt werden muss, können Sie u. U. direkt mit tail -f telefonieren.

Als etwas aufwendigere Alternative können Sie einen Blick auf die Implementierung von GNU End und Port werfen, die zu Java führen. (Ich bin nicht sicher, ob dies Ihren Code nicht bereits zu einer abgeleiteten Arbeit machen würde.)

0
Daniel Werner

Hier ist eine kurze Geschichte, die Sie als Zeiger verwenden können:

Ich habe TailingInputStream aus dem gleichen Grund bei der Arbeit codiert. Es verwendet grundsätzlich File und aktualisiert seinen Inhalt bei Bedarf und prüft es mit dem internen Puffer, wenn er sich signifikant geändert hat (4-KB-Speicherstempel IIRC) und dann das getan hat, was der tail -f macht. Ein bisschen hackig, ja, aber es funktioniert perfekt und verwirrt sich nicht mit Threads oder irgendetwas anderem - so ist es zumindest bis 1.4.2 kompatibel.

Das war jedoch viel einfacher als ReverseInputStream, das vom Ende der Datei bis zum Start ging und nicht starb, wenn die Datei im laufenden Betrieb aktualisiert wurde ...

0
Esko

Gerade stand das gleiche Problem - die "einfachste" Implementierung hier: Java Tail .

* Tolles Zeug * - fertig für die Produktion;)

Ich hoffe, dass die Code-Zitierung keine Lizenz fallen lässt.

    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(String[] 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]));
          String 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)]");
        }
      }
    }
0
ViPup