我需要实时读取最后添加到日志文件的行,并捕获正在添加的行。
类似于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"];
如何捕获尾部NSTask的输出?
这个方法有什么替代方法,我可以打开一个文件流,每次添加一行,然后在屏幕上输出? (基本日志记录功能)
答案 0 :(得分:4)
这样做有点棘手,因为readDataToEndOfFile
会等到tail
在返回之前关闭输出流,但tail -f
永远不会关闭输出流(stdout)。但是,实际上这对基本的C I / O代码来说非常简单,所以我创建了一个简单的FileTailer
类,您可以查看它。这不是什么花哨的东西,但它应该告诉你它是如何完成的。以下是FileTailer.h
,FileTailer.m
和test 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