NSTask / NSPipe从Unix命令读取 [英] NSTask/NSPipe read from Unix command
问题描述
我正在编写一个Cocoa应用程序,它需要执行一个UNIX程序,并在生成时逐行读取其输出。我设置一个NSTask和NSPipe如下:
task = [[NSTask alloc] init];
pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
// ... later ...
[task setArguments:...];
[task setLaunchPath:@...];
[任务启动];
handle = [[task fileHandleForReading] retain];
命令不会终止,直到程序通过任务终止]
。我已经尝试了从句柄读取的几种方法,如 -readInBackgroundAndNotify
, while([(data = [handle availableData])length]> 0)
和 -waitForDataInBackgroundAndNotify
,但管道从未似乎产生任何数据。是否有一些方法,我可以戳 NSTask
或 NSPipe
以清除数据?
EDIT : -readInBackgroundAndNotify
:
[handle readInBackgroundAndNotify];
notification_block_t handlerBlock =
^(NSNotification * notification){
NSData * data = [[notification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
/ * ... do stuff ... * /
[self addNotification:handle block:handlerBlock];
};
[self addNotification:handler block:handlerBlock];
// ...
- (void)addNotification:(id)handle block:(notification_block_t)block {
[[NSNotificationCenter defaultCenter]
addObserverForName:NSFileHandleReadCompletionNotification
object:handle
queue:[NSOperationQueue mainQueue]
usingBlock:block];
}
与 -waitForDataInBackgroundAndNotify
:
[handle waitForDataInBackgroundAndNotify];
notification_block_t handlerBlock =
^(NSNotification * notification){
NSData * data = [handle availableData];
/ * ... do stuff ... * /
};
[self addNotification:handler block:handlerBlock];
[self startProcessingThread:handle];
// ...
- (void)startProcessingThread:(NSFileHandle *)handle {
[[NSOperationQueue mainQueue]
addOperation:[[[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(dataLoop :)
object:handle] autorelease]];
}
- (void)dataLoop:(NSFileHandle *)handle {
NSData * data;
while([(data = [handle availableData])length]> 0){
/ * ... do stuff ... * /
}
}
EDIT 2 :参数设置如下(命令为
tshark
):NSArray * cmd = [NSArray arrayWithObjects:@ ,@http.request,
@ - Tfields,@ - Eseparator ='|',
@ - ehttp.host,@ - ehttp.request.method
@ - ehttp.request.uri,nil];
cmd = [[cmd arrayByAddingObjectsFromArray:[self.ports map:^(id arg1,NSUInteger idx){
return [NSString stringWithFormat:@ - d tcp.port ==%d,http [arg1 intValue]];
}]]
arrayByAddingObject:[@dststringByAppendingString:
[self.hosts componentsJoinedByString:@or dst]]];
[self.tsharktask setArguments:cmd];
解决方案这是一个工作示例, :
task = [[NSTask alloc] init];
[task setLaunchPath:...]
NSArray * arguments;
arguments = ...;
[task setArguments:arguments];
NSPipe * outPipe;
outPipe = [NSPipe pipe];
[task setStandardOutput:outPipe];
outFile = [outPipe fileHandleForReading];
[outFile waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(commandNotification :)
name:NSFileHandleDataAvailableNotification
object:nil];
[任务启动];
- (void)commandNotification:(NSNotification *)notification
{
NSData * data = nil;
while((data = [self.outFile availableData])&& [data length]){
...
}
}
I am writing a Cocoa application which needs to execute a UNIX program and read its output, line by line, as they are produced. I set up a NSTask and NSPipe as such:
task = [[NSTask alloc] init]; pipe = [NSPipe pipe]; [task setStandardOutput:pipe]; //... later ... [task setArguments:...]; [task setLaunchPath:@"..."]; [task launch]; handle = [[task fileHandleForReading] retain];
The command does not terminate until the program tells it to do so with
[task terminate]
. I have tried several methods of reading from the handle, such as-readInBackgroundAndNotify
,while([(data = [handle availableData]) length] > 0)
, and-waitForDataInBackgroundAndNotify
, but the pipe never seems to yield any data. Is there some way I can "poke" theNSTask
orNSPipe
to flush the data through?EDIT: with
-readInBackgroundAndNotify
:[handle readInBackgroundAndNotify]; notification_block_t handlerBlock = ^(NSNotification *notification) { NSData *data = [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem]; /*... do stuff ...*/ [self addNotification: handle block: handlerBlock]; }; [self addNotification: handler block: handlerBlock]; //... - (void)addNotification:(id)handle block:(notification_block_t)block { [[NSNotificationCenter defaultCenter] addObserverForName: NSFileHandleReadCompletionNotification object: handle queue: [NSOperationQueue mainQueue] usingBlock: block]; }
with
-waitForDataInBackgroundAndNotify
:[handle waitForDataInBackgroundAndNotify]; notification_block_t handlerBlock = ^(NSNotification *notification) { NSData *data = [handle availableData]; /*... do stuff ...*/ }; [self addNotification: handler block: handlerBlock];
with
while
loop:[self startProcessingThread: handle]; //... - (void)startProcessingThread:(NSFileHandle *)handle { [[NSOperationQueue mainQueue] addOperation: [[[NSInvocationOperation alloc] initWithTarget: self selector: @selector(dataLoop:) object: handle] autorelease]]; } - (void)dataLoop:(NSFileHandle *)handle { NSData *data; while([(data = [handle availableData]) length] > 0) { /*... do stuff ...*/ } }
EDIT 2: The arguments are set as follows (the command is
tshark
):NSArray *cmd = [NSArray arrayWithObjects:@"-R", @"http.request", @"-Tfields", @"-Eseparator='|'", @"-ehttp.host", @"-ehttp.request.method", @"-ehttp.request.uri", nil]; cmd = [[cmd arrayByAddingObjectsFromArray:[self.ports map:^(id arg1, NSUInteger idx) { return [NSString stringWithFormat:@"-d tcp.port==%d,http", [arg1 intValue]]; }]] arrayByAddingObject:[@"dst " stringByAppendingString: [self.hosts componentsJoinedByString:@" or dst "]]]; [self.tsharktask setArguments:cmd];
解决方案Here is a working example of how I usually do it:
task = [[NSTask alloc] init]; [task setLaunchPath:...]; NSArray *arguments; arguments = ...; [task setArguments:arguments]; NSPipe *outPipe; outPipe = [NSPipe pipe]; [task setStandardOutput:outPipe]; outFile = [outPipe fileHandleForReading]; [outFile waitForDataInBackgroundAndNotify]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commandNotification:) name:NSFileHandleDataAvailableNotification object:nil]; [task launch]; - (void)commandNotification:(NSNotification *)notification { NSData *data = nil; while ((data = [self.outFile availableData]) && [data length]){ ... } }
这篇关于NSTask / NSPipe从Unix命令读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!