2011-08-15 13 views
9

Me preguntaba cuál es la mejor manera de hacer que NSOutputStream redirija a la salida estándar. La técnica que uso en este momento es el uso de un flujo de salida que escribe en la memoria, obtener sus datos e imprimir que a la salida estándar:¿Cómo hacer que NSOutputStream redirija a la salida estándar?

NSOutputStream *stream = [[NSOutputStream alloc] initToMemory]; 
    [stream open]; 
    // calls to stream's -write:maxLengh: 
    NSData *data = [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; 
    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 
    printf("%s", [string UTF8String]); 
    [stream close]; 

¿Hay una mejor manera de lograr esto? En concreto, no estoy feliz por dos cosas con este enfoque:

  1. La necesidad de memoria adicional para datos que se escriben para transmitir

  2. Esta corriente no es reutilizable - después de haber recuperado los datos de esta corriente a través del [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey], la transmisión no se "restablece", es decir, quiero que las llamadas posteriores a este método me den solamente datos nuevos, pero no es el caso. Esto significa que tengo que crear un nuevo NSOutputStream cada vez que escribo en stdout.

Respuesta

11

No parece que haya una forma integrada de hacerlo. Si puede usar NSFileHandle en lugar de NSOutputStream, puede usar [NSFileHandle fileHandleWithStandardOutput]. Si usted tiene que utilizar NSOutputStream, intentar algo como esto:

// untested! 
@interface FileHandleOutputStream : NSOutputStream 
+ (FileHandleOutputStream *)outputStreamWithFileHandle:(NSFileHandle *)fileHandle; 
- (id)initWithFileHandle:(NSFileHandle *)fileHandle; 
@end 

@implementation FileHandleOutputStream { 
    NSFileHandle *_fileHandle; 
} 
+ (FileHandleOutputStream *)outputStreamWithFileHandle:(NSFileHandle *)fileHandle { 
    return [[[self alloc] initWithFileHandle:fileHandle] autorelease]; 
} 
- (id)initWithFileHandle:(NSFileHandle *)fileHandle { 
    if (self = [super init]) { 
     _fileHandle = [fileHandle retain]; 
    } 
    return self; 
} 
- (void)dealloc { 
    [_fileHandle release]; 
    [super dealloc]; 
} 
- (BOOL)hasSpaceAvailable { 
    return YES; 
} 
- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length { 
    [_fileHandle writeData:[NSData dataWithBytesNoCopy:buffer 
               length:length 
              freeWhenDone:NO]]; 
    return length; 
} 

Ahora usa

FileHandleOutputStream *myStrem = [FileHandleOutputStream outputStreamWithFileHandle: 
            [NSFileHandle fileHandleWithStandardOutput]]; 
+0

Conocí 'NSFileHandle', pero envolverlo dentro de una subclase de' NSOutputStream' no es algo en lo que haya pensado. Muy interesante, y ciertamente debería funcionar. –

+0

Aceptaré su respuesta tan pronto como haya verificado que esto funciona correctamente (sin embargo, no veo nada que vaya mal con esto). –

+0

Esto funciona muy bien. La única advertencia que puedo agregar es que, aparte de anular los métodos de 'NSOutputStream', puede que se requiera anular algunos métodos' NSStream' como '-open' o' -close'. Gracias por la ayuda. –

-1

También puede abrir un NSOutputStream a la salida estándar utilizando "/ dev/tty" que el archivo. ("/ Dev/tty" es la designación de Unix para la entrada y salida estándar.)

De este modo se puede crear una norma NSOutputStream a cabo con:

NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath: @"/dev/tty" 
                  append: NO]; 

Un inconveniente es que esto no funcionará si ejecuta su programa dentro de Xcode; Tendrás que ejecutarlo en una ventana de terminal.

+1

'/ dev/tty' es el terminal de control de un proceso, no la salida o entrada estándar. Esto fallará si, por ejemplo, redirecciono stdout a un archivo. En este caso, 'dev/tty' todavía mostrará la salida en el terminal, lo cual es incorrecto. –

Cuestiones relacionadas