2011-08-15 2 views
9

Je me demandais quel est le meilleur moyen de rediriger NSOutputStream vers la sortie standard. La technique que je me sers est en ce moment d'utiliser un flux de sortie qui écrit à la mémoire, obtenir ses données et imprimer que la sortie standard:Comment faire pour rediriger NSOutputStream vers la sortie standard?

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]; 

Y at-il une meilleure façon d'y parvenir? Plus précisément, je ne suis pas content de deux choses avec cette approche:

  1. Le besoin de mémoire supplémentaire pour les données écrites pour diffuser

  2. Ce flux n'est pas réutilisable - après avoir récupéré les données de ce flux via [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey], le flux n'est pas "réinitialisé" c'est-à-dire que je veux que les appels suivants à cette méthode ne me donnent que de nouvelles données, mais ce n'est pas le cas. Cela signifie que je dois créer un nouveau NSOutputStream après chaque écriture dans stdout.

Répondre

11

Il ne semble pas y avoir de façon intégrée de le faire. Si vous pouvez utiliser NSFileHandle au lieu de NSOutputStream, vous pouvez utiliser [NSFileHandle fileHandleWithStandardOutput]. Si vous devez utiliser NSOutputStream, essayer quelque chose comme ceci:

// 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; 
} 

maintenant utiliser

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

Je connaissais 'NSFileHandle', mais envelopper dans une sous-classe de' NSOutputStream' n'est pas quelque chose que je pensais. Très intéressant, et ça devrait certainement marcher. –

+0

Je vais accepter votre réponse dès que j'ai vérifié que cela fonctionne correctement (je ne vois pas tout ce qui devrait aller mal avec cela si). –

+0

Cela fonctionne très bien. La seule mise en garde que je peux ajouter est qu'en dehors des méthodes de remplacement de 'NSOutputStream', il peut être nécessaire de remplacer certaines méthodes' NSStream' comme '-open' ou' -close'. Merci pour l'aide. –

-1

Vous pouvez également ouvrir un NSOutputStream à stdout en utilisant "/ dev/tty" que le fichier. («/Dev/tty » est la désignation Unix pour l'entrée et la sortie standard.)

Ainsi, vous pouvez créer un NSOutputStream à la norme avec:

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

Un inconvénient est que cela ne fonctionnera pas si vous exécutez votre programme dans Xcode; vous devrez l'exécuter dans une fenêtre de terminal.

+1

'/ dev/tty' est le terminal de contrôle d'un processus, pas la sortie ou l'entrée standard. Cela échouera si, disons, je redirige stdout vers un fichier. Dans ce cas, 'dev/tty' montrera toujours la sortie sur le terminal, ce qui est faux. –

Questions connexes