Frage

Ich brauche die zuletzt hinzugefügten Zeile zu einer Log-Datei , in Echtzeit zu lesen, und zu erfassen, dass Zeile hinzugefügt werden.

Etwas ähnliches wie tail -f.

So mein erster Versuch war Schwanz zu verwenden -f NSTask.

Ich kann keine Ausgabe sehen mit dem Code unten:

    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);

kann ich die Ausgabe sehen, wie erwartet bei der Verwendung von:

[server setLaunchPath:@"/bin/ls"];
  1. Wie kann ich die Ausgabe dieses Schwanz einzufangen NSTask?

  2. Gibt es eine Alternative zu diesem Verfahren, in dem ich eine Stream-Datei öffnen kann und jedes Mal, wenn eine Zeile hinzugefügt wird, gibt sie auf dem Bildschirm? (Grund Logging-Funktionalität)

War es hilfreich?

Lösung

Dies ist ein wenig schwierig Weg zu tun, wie readDataToEndOfFile warten, bis tail vor der Rückkehr in den Ausgangsstrom schließt, aber tail -f schließt nie den Ausgangsstrom (stdout). Aber das ist eigentlich ziemlich einfach mit grundlegenden C I / O-Code zu tun, so dass ich eine einfache FileTailer Klasse aufgepeitscht, dass Sie überprüfen können. Es ist nichts Besonderes, aber es sollte Ihnen zeigen, wie es gemacht wird. Here're die Quellen für FileTailer.h , FileTailer.m und ein Testfahrer .

Das Fleisch der Klasse ist ziemlich einfach. Sie geben es einen Block, und es liest ein Zeichen aus dem Strom (wenn möglich) und übergibt sie an den Block; wenn EOF erreicht ist, wartet er eine Anzahl von Sekunden (durch refresh bestimmt) und dann versucht, den Strom wieder zu lesen.

- (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];
        }
    }
}

Sie können es nennen ziemlich einfach, wie folgt aus:

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

(Caveat: Ich habe die FileTailer Klasse schrieb ziemlich schnell, so dass es jetzt Art von hässlich ist richtig und sollte ein wenig gereinigt werden, aber es sollte als ein anständiges Beispiel dienen, wie eine Datei auf unbestimmte Zeit zu lesen, à la tail -f.)

Andere Tipps

Hier ist auch ein Weg "tail -f Logfile" über NSTask in Objective-C zu verwenden:

asynctask.m - Beispielcode, der zeigt, wie asynchronen stdin, stdout und stderr Streams für mit NSTask Verarbeitung von Daten implementieren

...

eine GUI-Anwendung weniger zu sein (das heißt a-Foundation basiertes Befehlszeilenprogramm), läuft einen asynctask.m NSRunLoop manuell die Verwendung von asynchronen „waitForDataInBackgroundAndNotify“ Benachrichtigungen zu ermöglichen. Darüber hinaus asynctask.m Verwendungen pthread_create (3) und pthread_detach (3) für mehr als 64 KB zum stdin eines NSTask schreiben.

Der Quellcode von asynctask.m unter: http://www.cocoadev.com/index .pl? NSPipe

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top