Как получить что-то похожее на Tail -f с помощью NSTask - PullRequest
3 голосов
/ 12 января 2011

Мне нужно прочитать последнюю добавленную строку в файл журнала в режиме реального времени и записать добавляемую строку.

Что-то похожее на Tail -f.

Итак, моей первой попыткой было использование Tail -f с использованием NSTask.

Я не вижу никаких выходных данных, используя следующий код:

    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. Есть ли альтернатива этому методу, где я могуоткрыть поток в файл и при каждом добавлении строки выводить его на экран?(базовая функциональность регистрации)

Ответы [ 2 ]

4 голосов
/ 13 января 2011

Это немного сложно, так как readDataToEndOfFile будет ждать, пока tail не закроет выходной поток, прежде чем вернуться, но tail -f никогда не закроет выходной поток (stdout). Однако на самом деле это довольно просто сделать с базовым кодом ввода / вывода C, поэтому я создал простой класс FileTailer, который вы можете проверить. Это не что-то необычное, но оно должно показать вам, как это делается. Вот источники FileTailer.h, FileTailer.m и тестового драйвера .

Мясо этого класса довольно просто. Вы передаете ему блок, и он читает символ из потока (если это возможно) и передает его в блок; если достигнуто значение 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 довольно быстро, так что он сейчас немного уродлив и его нужно немного почистить, но он должен послужить хорошим примером того, как читать файл бесконечно, à la tail -f.)

1 голос
/ 14 января 2011

Вот способ использования "tail -f logfile" через NSTask в Objective-C:

asynctask.m - пример кода, который показывает, как реализовать асинхронные потоки stdin, stdout & stderr дляОбрабатывая данные с помощью NSTask

...

Будучи приложением без GUI (т.е. инструментом командной строки на основе Foundation), asynctask.m запускает NSRunLoop вручную, чтобы разрешить использование асинхронного "waitForDataInBackgroundAndNotify "уведомления.Кроме того, asynctask.m использует pthread_create (3) и pthread_detach (3) для записи более 64 КБ в stdin NSTask.

Исходный код asynctask.m доступен по адресу: http://www.cocoadev.com/index.pl?NSPipe

...