【问题标题】:How to make NSOutputStream redirect to standard output?如何使 NSOutputStream 重定向到标准输出?
【发布时间】:2011-10-27 02:00:22
【问题描述】:

我想知道将NSOutputStream 重定向到标准输出的最佳方法是什么。我现在使用的技术是使用写入内存的输出流,获取其数据并将其打印到标准输出:

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

有没有更好的方法来实现这一点?具体来说,我对这种方法有两点不满意:

  1. 写入流的数据需要额外的内存

  2. 这个流是不可重用的——在我通过[stream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]从这个流中检索数据之后,流不是“重置”的,即我希望后续调用这个方法只给我新数据,但它的不是这样。这意味着我每次写入标准输出后都必须创建一个新的 NSOutputStream。

【问题讨论】:

    标签: objective-c cocoa io


    【解决方案1】:

    似乎没有内置的方法可以做到这一点。如果可以使用NSFileHandle 代替NSOutputStream,则可以使用[NSFileHandle fileHandleWithStandardOutput]。如果您必须使用NSOutputStream,请尝试以下操作:

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

    现在使用

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

    【讨论】:

    • 我知道NSFileHandle,但是将它包装在NSOutputStream 的子类中并不是我想到的。非常有趣,它肯定会起作用。
    • 我会在确认这可以正常工作后立即接受您的回答(不过我看不出有什么问题)。
    • 这很好用。我可能要补充的唯一警告是,除了覆盖NSOutputStream 的方法之外,可能还需要覆盖一些NSStream 方法,例如-open-close。感谢您的帮助。
    【解决方案2】:

    这里不需要 Cocoa 提供自己的构造函数,因为 stdout 可以作为“文件”使用。不幸的是,这似乎没有记录在案,但效果很好:

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

    您也可以使用 stderr 做同样的事情(或使用 NSInputStream 作为标准输入)。

    【讨论】:

      【解决方案3】:

      您还可以使用“/dev/tty”作为文件打开一个 NSOutputStream 到标准输出。 (“/dev/tty”是标准输入和输出的 Unix 名称。)

      因此,您可以创建一个 NSOutputStream 来标准输出:

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

      一个缺点是,如果您在 Xcode 中运行程序,这将不起作用;您必须在终端窗口中运行它。

      【讨论】:

      • /dev/tty 是进程的控制终端,而不是标准输出或输入。如果我将标准输出重定向到文件,这将失败。在这种情况下,dev/tty 仍然会在终端上显示输出,这是错误的。
      猜你喜欢
      • 1970-01-01
      • 2020-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      相关资源
      最近更新 更多