2011-01-12 4 views
3

ログファイルに最後に追加した行をリアルタイムで読み込み、その行を追加する必要があります。NSTaskを使用してテール-fに似たものを得るには

Tail -fと類似しています。

私の最初の試みはNSTaskを使ってテール-fを使うことでした。

私は以下のコードを使用して、任意の出力を参照することはできません。

NSTask *server = [[NSTask alloc] init]; 
    [server setLaunchPath:@"/usr/bin/tail"]; 
    [server setArguments:[NSArray arrayWithObjects:@"-f", @"/path/to/my/LogFile.txt",nil]]; 

    NSPipe *outputPipe = [NSPipe pipe]; 
    [server setStandardInput:[NSPipe pipe]]; 
    [server setStandardOutput:outputPipe]; 

    [server launch]; 
    [server waitUntilExit]; 
    [server release]; 

    NSData *outputData = [[outputPipe fileHandleForReading] readDataToEndOfFile]; 
    NSString *outputString = [[[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding] autorelease]; 
    NSLog (@"Output \n%@", outputString); 

使用した場合、予想通り、私は出力を見ることができます:

[server setLaunchPath:@"/bin/ls"]; 
  1. どのように私はの出力をキャプチャすることができますがその尾NSTask?

  2. ファイルへのストリームを開くことができ、行が追加されるたびに画面に出力するこの方法の代替手段はありますか? (基本的なロギング機能)

答えて

4

tailが戻る前に、出力ストリームを閉じますが、tail -fは、出力ストリーム(標準出力)をクローズすることはありませんまでreadDataToEndOfFileが待機するように、これは、あなたの方法を行うには少しトリッキーです。しかし、これは実際には基本的なCのI/Oコードで行うのはかなり簡単なので、チェックアウトできる簡単なFileTailerクラスを作成しました。それは素晴らしいことではありませんが、どのようにそれが完了したかを示す必要があります。ここにはFileTailer.hFileTailer.m、およびtest driverのソースがあります。

クラスの肉はかなりシンプルです。ブロックを渡し、ストリームから文字を読み込み(可能であれば)ブロックに渡します。 EOFに達していれば、数秒待って(refreshで決まる)、ストリームを再度読み取ろうとします。

- (void)readIndefinitely:(void (^)(int ch))action 
{ 
    long pos = 0L; 
    int ch = 0; 

    while (1) { 
     fseek(in, pos, SEEK_SET); 
     int ch = fgetc(in); 
     pos = ftell(in); 
     if (ch != EOF) { 
      action(ch); 
     } else { 
      [NSThread sleepForTimeInterval:refresh]; 
     } 
    } 
} 

あなたはこのように、かなり単純にそれを呼び出すことができます。

FileTailer *tail = [[[FileTailer alloc] initWithStream:stdin refreshPeriod:3.0] autorelease]; 
[tail readIndefinitely:^ void (int ch) { printf("%c", ch); }]; 

(警告:私はかなり速いFileTailerクラスを書いたので、それが今のような醜いだとビットをクリーンアップする必要がありますが、それはラtail -f A、無期限にファイルを読み取る方法についてまともな例として役立つはずです)

+0

は、それがループを通過するごとに 'fseek'呼び出す必要ですか? 'fgetc'が' EOF'を返した後でも呼び出す必要がありますか? – benzado

+0

素晴らしいです、私はちょうど主なものをブロックしないために別のスレッドでそれを実行しなければなりませんでした。解決策を書くために時間mipadiを取ってくれてありがとう。ほんとうにありがとう! – Bach

+0

@benzado:厳密に言えば、いいえ。あなたは 'ftell'呼び出しをスレッドがスリープする直前に移動させ、その後ウェイクアップした後に' fseek'を呼び出すことができます。このコードは少し簡略化されています。 – mipadi

1

ここでObjective-CでNSTaskを経由して、「ログファイル-f尾」を使用する方法です:。

asynctask.m - 非同期STDIN、NSTask

とデータを処理するためのSTDOUT & stderrのストリームを実装する方法を示すサンプルコード...

GUIレスアプリケーションである(すなわち、 Foundationベースのコマンドラインツール)では、asynctask.mは非同期の "waitForDataInBackgroundAndNotify"通知を有効にするために手動でNSRunLoopを実行します( )。さらに、asynctask.m は、NSTaskのstdinに64 KB以上を書き込むためにpthread_create(3)およびpthread_detach(3)を使用します。で利用可能asynctask.mの

ソースコード:http://www.cocoadev.com/index.pl?NSPipe

関連する問題