NSTask / usr / bin / compress,循环写入standardInput,通过阻塞availableData读取standardOutput

时间:2014-02-24 19:44:36

标签: cocoa nstask

我正在尝试使用/ usr / bin / compress压缩文件,在没有文件名的情况下启动,以便从stdin获取数据并将压缩数据写入stdout。我用standardInput,Output& amp;管道创建任务。错误。在循环中,我从文件中读取一个数据块,写入任务的stdin,然后使用[NSFileHandle availableData]从stdout读取。我尝试过块大小为2K,8K和12K。在所有情况下,我的程序都会挂起。我的目标是10.6

我的代码结构的方式,我更喜欢它阻止在availableData上,因为在数据到达之前我不能做任何事情,并且调用者只在处理完成时才会返回。到目前为止,这都是主线程。一旦它工作,我将把这个部分移动到一个单独的线程,以便不阻塞main,是的,然后我需要让调用者在下级线程退出时接受异步完成。

init
{
    self = [super init];
    if (self) {
        task = [[NSTask alloc] init];
        NSPipe* stdin_Pipe = [NSPipe pipe];
        NSPipe* stdoutPipe = [NSPipe pipe];
        NSPipe* stderrPipe = [NSPipe pipe];

        [task setStandardInput:  stdin_Pipe];
        [task setStandardOutput: stdoutPipe];
        [task setStandardError:  stderrPipe];
        [task setLaunchPath: kCompressor];

        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver: self
               selector: @selector (taskTerminated:)
                   name: NSTaskDidTerminateNotification
                 object: task];
        [task launch];
    }
    return self;
}
写一些,读一些。什么都没说压缩决定写什么。

(NSData*) compressData: (NSData*) source
{
    [[[task standardInput] fileHandleForWriting] writeData: source];
    return [[[task standardOutput] fileHandleForReading] availableData];
}

...以及使用上一个代码段的代码:

(BOOL) compressFile: (NSString*) file
{
    //...
    NSData* fileDataBlock = [sourceFileHandle readDataOfLength: kTargetFileReadBlockLen];
    while ( [fileDataBlock length] > 0) {
        NSData* compressedData = [origFileCompress compressData: currentBuffer];
        //...
    }
}

gdb显示我的程序执行此操作(最新帧):

读取$ UNIX2003中的

0x9a0ade5e

_NSReadFromFileDescriptor

中的

0x91ebcc13

0x91ec3c64 in - [NSConcreteFileHandle availableData]

0x00002e8b in - [压缩compressData:]在CompressIt.m:266

活动监视器 - >示例流程显示/ usr / bin / compress执行此操作(最早的帧):

2672 fread(在libSystem.B.dylib中)+ 436 [0x7fff8a0e501a]

2672 __srefill1(在libSystem.B.dylib中)+ 27 [0x7fff8a0e50a5]

2672 _sread(在libSystem.B.dylib中)+ 19 [0x7fff8a0dce34]

2672 __sread(在libSystem.B.dylib中)+ 16 [0x7fff8a0e50ef]

2672读取$ NOCANCEL(在libSystem.B.dylib中)+ 10 [0x7fff8a095982]

1 个答案:

答案 0 :(得分:0)

你无法控制compress的工作方式 - 缓冲,输入与输出的关系等等 - 所以写一个块然后再读一个就不太可能了。

你显然知道线程(你打算稍后将代码移出主线程),所以只需将数据写入另一个线程中的管道 - 你可以使用GCD调度并发块,激活{{1一旦你这样做,你就把你的写作分解为&从管道中读取,他们每个人都可以按照自己的节奏前进。