开发者

How to make NSOutputStream redirect to standard output?

I was wondering what's the best way to make NSOutputStream redirect to standard output. The technique I am using right now is to use an output stream that writes to memory, get its data and print that to stdout:

开发者_StackOverflow  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];

Is there a better way to achieve this? Specifically, I am not happy about two things with this approach:

  1. The need for extra memory for data that is written to stream

  2. This stream is not reusable -- after I have retrieved data from this stream via [stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey], the stream is not "reset" i.e. I want subsequent calls to this method to give me only new data, but its not the case. This means that I have to create a new NSOutputStream after every time I write to stdout.


It doesn't appear there's a built-in way to do this. If you can use NSFileHandle instead of NSOutputStream, you can use [NSFileHandle fileHandleWithStandardOutput]. If you have to use NSOutputStream, try something like this:

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

Now use

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


There's no need for Cocoa to provide its own constructor here because stdout is available as a "file." This doesn't seem to be documented, unfortunately, but works very well:

NSOutputStream *outputStream =
    [NSOutputStream outputStreamToFileAtPath:@"/dev/stdout"
                                      append:NO];

You can do the same thing with stderr as well (or use a NSInputStream for stdin).


You can also open a NSOutputStream to stdout using "/dev/tty" as the file. ("/dev/tty" is the Unix designation for standard input and output.)

Thus you can create a NSOutputStream to standard out with:

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

A drawback is that this won't work if you run your program within Xcode; you'll have to run it in a terminal window.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜