【问题标题】:How do I get something similar to Tail -f using NSTask如何使用 NSTask 获得类似于 Tail -f 的内容
【发布时间】:2011-01-12 01:26:28
【问题描述】:

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

类似于 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. 是否有任何替代此方法的方法,我可以在其中打开一个流到文件,并且每次添加一行时,将其输出到屏幕上? (基本的日志记录功能)

【问题讨论】:

    标签: objective-c tail nstask


    【解决方案1】:

    这有点棘手,因为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 类非常快,所以它现在有点难看,应该清理一下,但它应该作为一个关于如何无限期读取文件的好例子, à la tail -f.)

    【讨论】:

    • 是否有必要在每次通过循环时调用fseekfgetc返回EOF后是否还要调用它?
    • 效果很好,我只需要在另一个线程上运行它就不会阻塞主线程。感谢您花时间 mipadi 编写解决方案。我真的很感激!
    • @benzado:严格来说,没有。您可以将ftell 调用移到线程休眠之前,然后只在它唤醒后调用fseek;这段代码有点简化。
    【解决方案2】:

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

    asynctask.m -- 示例代码展示了如何实现异步标准输入、标准输出和标准错误流以使用 NSTask 处理数据

    ...

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

    asynctask.m 的源代码位于:http://www.cocoadev.com/index.pl?NSPipe

    【讨论】:

      猜你喜欢
      • 2015-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-08
      • 2010-10-05
      • 1970-01-01
      • 2010-09-13
      相关资源
      最近更新 更多