Come faccio ad avere qualcosa di simile a tail -f utilizzando NSTask
-
10-10-2019 - |
Domanda
Ho bisogno di leggere l'ultima riga aggiunta ad un file di log , in tempo reale, e la cattura quella linea viene aggiunto.
Qualcosa di simile a tail -f.
Quindi il mio primo tentativo è stato quello di usare tail -f utilizzando NSTask.
Non riesco a vedere alcun output utilizzando il codice qui sotto:
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);
posso vedere l'output come previsto quando si utilizza:
[server setLaunchPath:@"/bin/ls"];
-
Come posso catturare l'output di quella coda NSTask?
-
C'è qualche alternativa a questo metodo, dove posso aprire un flusso di file e ogni volta che si aggiunge una linea, uscita sullo schermo? (Funzionalità di registrazione di base)
Soluzione
Questo è un po 'difficile da fare la tua strada, come readDataToEndOfFile
attenderà fino a quando tail
chiude il flusso di output prima di tornare, ma tail -f
non chiude mai il flusso di output (stdout). Tuttavia, questo è in realtà piuttosto semplice da fare con la base C di I / O di codice, così ho montata su una semplice classe FileTailer
che si possono verificare. Non è niente di eccezionale, ma dovrebbe mostrare come si fa. Here're le fonti per FileTailer.h
, FileTailer.m
, e un collaudatore .
La carne della classe è abbastanza semplice. Si passa un blocco, e si legge un carattere dal flusso (se possibile) e lo passa al blocco; se EOF è stato raggiunto, si aspetta un certo numero di secondi (determinato da refresh
) e poi cerca di leggere nuovamente il flusso.
- (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];
}
}
}
Si può chiamare abbastanza semplicemente, in questo modo:
FileTailer *tail = [[[FileTailer alloc] initWithStream:stdin refreshPeriod:3.0] autorelease];
[tail readIndefinitely:^ void (int ch) { printf("%c", ch); }];
(Caveat: ho scritto la classe FileTailer
piuttosto veloce, quindi è una specie di brutto momento e deve essere ripulito un po ', ma dovrebbe servire da esempio decente su come leggere un file a tempo indeterminato, à la tail -f
.)
Altri suggerimenti
Ecco un modo di usare "file di log tail -f" via NSTask in Objective-C:
asynctask.m - codice di esempio che mostra come implementare stdin, stdout flussi e stderr asincroni per l'elaborazione dei dati con NSTask
...
Essendo un'applicazione GUI-less (vale a dire uno strumento a riga di comando Fondazione-based), asynctask.m gestisce un NSRunLoop manualmente per consentire l'utilizzo di asincroni notifiche "waitForDataInBackgroundAndNotify". Inoltre, asynctask.m Usi pthread_create (3) e pthread_detach (3) per la scrittura di più di 64 KB alla stdin di un NSTask.
Il codice sorgente di asynctask.m disponibile all'indirizzo: http://www.cocoadev.com/index .pl? NSPipe