2012-11-15 9 views
6

Piszę aplikację Cocoa, która musi wykonać program UNIX i odczytać jej wynik, linia po linii, ponieważ są one produkowane. Założyłem NSTask i NSPipe jako takie:NSTask/NSPipe odczytano z polecenia Unixa

task = [[NSTask alloc] init]; 
pipe = [NSPipe pipe]; 
[task setStandardOutput:pipe]; 
//... later ... 
[task setArguments:...]; 
[task setLaunchPath:@"..."]; 
[task launch]; 
handle = [[task fileHandleForReading] retain]; 

Komenda nie kończy aż program mówi, że aby to zrobić z [task terminate]. Próbowałem kilku metod czytania z uchwytu, takich jak -readInBackgroundAndNotify, while([(data = [handle availableData]) length] > 0) i -waitForDataInBackgroundAndNotify, ale rura nigdy nie wydaje żadnych danych. Czy istnieje sposób, aby "poke" "NSTask lub NSPipe przepłukać dane przez?

EDIT: z -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]; 
} 

z -waitForDataInBackgroundAndNotify:

[handle waitForDataInBackgroundAndNotify]; 
notification_block_t handlerBlock = 
    ^(NSNotification *notification) { 
     NSData *data = [handle availableData]; 
     /*... do stuff ...*/ 
    }; 
[self addNotification: handler block: handlerBlock]; 

z while pętli:

[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: Argumenty są następujące (komenda jest 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]; 
+0

Prześlij cały swój kod (np. Jak zdefiniowano NSFileHandleDataAvailableNotification). –

+1

'typedef (^ notification_block_t) (NSNotification *);', oczywiście. – Actorclavilis

Odpowiedz

8

Oto przykład pracy, jak zwykle zrobić:

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]){ 
     ... 
    } 
} 
+0

Również, jak ustawić argumenty (proszę wpisać kod)? –

+1

To działa dobrze, ale odczytuje dane wyjściowe z mojego polecenia w 4096 blokach bajtów, co jest mniej niż optymalne, ponieważ chciałbym mieć dane dostępne, gdy tylko "tshark" je wyprodukuje. – Actorclavilis

+0

Dodałem także "-map:" do "NSArray" jako kategorię. – Actorclavilis

1

Oto rozwiązanie asynchroniczny uzyskania wyjście zadanie .

task.standardOutput = [NSPipe pipe]; 
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { 
NSData *data = [file availableData]; // this will read to EOF, so call only once 
NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

// if you're collecting the whole output of a task, you may store it on a property 
//maybe you want to appenddata 
//[weakself.taskOutput appendData:data]; 
}]; 

nadzieja może pomóc komuś.

Powiązane problemy