74

Linux コマンド「tail -f」の機能を実装するために、どの手法やライブラリを使用すればよいか考えています。基本的に のアドオン/交換品を探していjava.io.FileReaderます。クライアント コードは次のようになります。

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
}

欠けている部分は、 の合理的な実装ですTailFileReader。ファイルが開かれる前に存在するファイルの一部と、追加された行を読み取ることができる必要があります。

4

9 に答える 9

60

Tailerクラスの Apache Commons 実装を見てください。ログのローテーションも処理しているようです。

于 2011-02-08T19:48:37.363 に答える
41

ファイルの読み取りを続行し、ファイルがさらに更新されるまで待機する機能は、コードで自分で達成するのはそれほど難しくありません。ここにいくつかの擬似コードがあります:

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
    }
}

このタイプの機能を独自のスレッドに配置して、スリープさせてアプリケーションの他の領域に影響を与えないようにすることをお勧めします。セッターで公開keepReadingして、メインクラス/アプリケーションの他の部分が、単に呼び出しなどを行うだけで、他の頭痛の種なしにスレッドを安全にシャットダウンできるようにする必要がありますstopReading()

于 2009-02-17T19:01:00.790 に答える
13

このロジックを実行するJLogTailerを確認してください。

コードの主なポイントは次のとおりです。

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();
}
于 2009-02-17T23:11:52.073 に答える
9

少し前に、Scala で「tail -f」の短い実装を作成しました: tailf。ファイルのローテーションも処理し、EOF に達したとき、またはファイルの名前が変更されたときに何をするかを独自のロジックを定義できます。

実際には複雑なものは何もないので、Java に移植することができます。いくつかの注意事項: メイン ファイルはTail.scalaであり、基本的にFollowingInputStream、EOF/名前変更とfollowメソッドを処理するものを定義FollowingInputStreamSequenceInputStreamます。したがって、FollowingInputStream終了するとすぐに、SequenceInputStreamから次の要素を要求しEnumeration、別の要素FollowingInputStreamが作成されます。

于 2010-12-04T23:06:46.413 に答える
1

この素敵なテール実装を見つけました。

著者:アメランドリ

ソース: 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)]");
        }
      }

}
于 2016-10-25T17:23:03.880 に答える
1

コードを Unix システムでのみ実行する必要がある場合は、シェルを実行して直接呼び出すだけで済む場合がありますtail -f

より複雑な代替手段として、GNU tail の実装を見て、それを Java に移植することができます。(ただし、これでコードが派生物にならないかどうかはわかりません。)

于 2010-12-02T20:54:07.017 に答える
0

同じ問題に直面しただけです-ここで「最も単純な」実装が見つかりました: Java Tail

*素晴らしいもの* -生産の準備ができました;)

コード引用によってライセンスが失われないことを願っています。

    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)]");
        }
      }
    }
于 2012-09-14T08:11:16.690 に答える
-1

以下は、ポインターとして使用できる短いストーリーです。

まったく同じ理由で、職場で TailingInputStream をコーディングしました。基本的にファイルを使用し、その内容をオンデマンドで更新し、大幅に変更された場合 (4kB メモリ スタンプ IIRC) を内部バッファーに対してチェックし、tail -f の動作を実行します。はい、少しハックですが、完全に機能し、スレッドやそのような派手なものを台無しにすることはありません.少なくとも1.4.2まで互換性があります.

そうは言っても、ファイルの最後から最初に移動し、ファイルがその場で更新されても死ななかったReverseInputStreamよりもはるかに簡単でした...

于 2009-02-17T19:35:11.987 に答える