我如何使用 NSTask 获得类似于 Tail -f 的东西

Bac*_*ach 4 objective-c tail nstask

我需要实时将最后添加的行读取到日志文件中,并捕获添加的那一行。

类似于 Tail -f 的东西。

所以我的第一次尝试是使用 NSTask 使用 Tail -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);
Run Code Online (Sandbox Code Playgroud)

使用时我可以看到预期的输出:

[server setLaunchPath:@"/bin/ls"];
Run Code Online (Sandbox Code Playgroud)
  1. 如何捕获该尾部 NSTask 的输出?

  2. 这种方法有什么替代方法,我可以打开一个流到文件,每次添加一行时,将它输出到屏幕上?(基本日志功能)

mip*_*adi 5

这样做有点棘手,因为在返回之前readDataToEndOfFile会等到tail关闭输出流,但tail -f永远不会关闭输出流(stdout)。然而,这对于基本的 CI/O 代码来说实际上非常简单,所以我创建了一个简单的FileTailer类,您可以查看。这不是什么花哨的东西,但它应该向您展示它是如何完成的。我这里还有的来源FileTailer.hFileTailer.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];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以很简单地称呼它,像这样:

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

(警告:我写这个FileTailer类的速度很快,所以它现在有点难看,应该清理一下,但它应该作为一个关于如何无限期读取文件的好例子,à la tail -f。)