如何使用NSTask获得类似于Tail -f的内容

时间:2011-01-12 01:26:29

标签: 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);

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

[server setLaunchPath:@"/bin/ls"];
  1. 如何捕获尾部NSTask的输出?

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

2 个答案:

答案 0 :(得分:4)

这样做有点棘手,因为readDataToEndOfFile会等到tail在返回之前关闭输出流,但tail -f永远不会关闭输出流(stdout)。但是,实际上这对基本的C I / O代码来说非常简单,所以我创建了一个简单的FileTailer类,您可以查看它。这不是什么花哨的东西,但它应该告诉你它是如何完成的。以下是FileTailer.hFileTailer.mtest 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类速度非常快,所以它现在很难看,应该稍微清理一下,但它应该作为如何读取文件的一个很好的例子无限期地,àlatail -f。)

答案 1 :(得分:1)

这是在Objective-C中通过NSTask使用“tail -f logfile”的方法:

  

asynctask.m - 示例代码,演示如何实现异步stdin,stdout&用于使用NSTask

处理数据的stderr流      

...

     

作为无GUI的应用程序(即基于Foundation的命令行工具),asynctask.m手动运行NSRunLoop   启用异步“waitForDataInBackgroundAndNotify”通知。另外,asynctask.m   使用pthread_create(3)和pthread_detach(3)将超过64 KB写入NSTask的stdin。

asynctask.m的源代码,地址:http://www.cocoadev.com/index.pl?NSPipe