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

发布于 2024-10-11 09:26:55 字数 999 浏览 8 评论 0 原文

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

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

I need to read the last added line to a log file, in realtime, and capture that line being added.

Something similar to Tail -f.

So my first attempt was to use Tail -f using NSTask.

I can't see any output using the code below:

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

I can see the output as expected when using:

[server setLaunchPath:@"/bin/ls"];
  1. How can i capture the output of that tail NSTask?

  2. Is there any alternative to this method, where I can open a stream to file and each time a line is added, output it on screen? (basic logging functionality)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独享拥抱 2024-10-18 09:26:55

按照您的方式执行此操作有点棘手,因为 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];
        }
    }
}

您可以非常简单地调用它,如下所示:

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

(注意:我很快就编写了 FileTailer 类,因此它现在有点丑陋,应该清理一下,但它应该可以使用作为一个关于如何无限期地读取文件的不错的例子,à la tail -f。)

This is a little tricky to do your way, as readDataToEndOfFile will wait until tail closes the output stream before returning, but tail -f never closes the output stream (stdout). However, this is actually pretty simple to do with basic C I/O code, so I whipped up a simple FileTailer class that you can check out. It's not anything fancy, but it should show you how it's done. Here're the sources for FileTailer.h, FileTailer.m, and a test driver.

The meat of the class is pretty simple. You pass it a block, and it reads a character from the stream (if possible) and passes it to the block; if EOF has been reached, it waits a number of seconds (determined by refresh) and then tries to read the stream again.

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

You can call it pretty simply, like this:

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

(Caveat: I wrote the FileTailer class pretty fast, so it's kind of ugly right now and should be cleaned up a bit, but it should serve as a decent example on how to read a file indefinitely, à la tail -f.)

挽清梦 2024-10-18 09:26:55

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

asynctask.m——演示如何实现异步 stdin、stdout 和 stdout 的示例代码。用于使用 NSTask 处理数据的 stderr 流

...

作为一个无 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

Here's a way to use "tail -f logfile" via NSTask in Objective-C:

asynctask.m -- sample code that shows how to implement asynchronous stdin, stdout & stderr streams for processing data with NSTask

...

Being a GUI-less application (i.e. a Foundation-based command line tool), asynctask.m runs an NSRunLoop manually
to enable the use of asynchronous "waitForDataInBackgroundAndNotify" notifications. In addition, asynctask.m
uses pthread_create(3) and pthread_detach(3) for writing more than 64 KB to the stdin of an NSTask.

Source code of asynctask.m available at: http://www.cocoadev.com/index.pl?NSPipe

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文