繁体   English   中英

Objective-C,NSTask 缓冲区限制

[英]Objective-C, NSTask Buffer Limitation

我正在使用NSTask运行一个返回一长串数据的外部实用程序。 问题在于,当返回的字符串超过大量数据(大约 32759 个字符)时,它会变为null或截断返回的字符串。 如何返回完整输出?

NSTask *myTask = [[NSTask alloc] init];

[myTask setLaunchPath:myExternalCommand];
[myTask setArguments:[NSArray arrayWithObjects: arg1, arg2, nil]];

NSPipe *pipe = [NSPipe pipe];
[myTask setStandardOutput:pipe];

NSFileHandle *taskHandle;
taskHandle = [pipe fileHandleForReading];

[myTask launch];
[myTask waitUntilExit];

NSData *taskData;
taskData = [taskHandle readDataToEndOfFile];

NSString *outputString = [[NSString alloc] initWithData:taskData
                         encoding:NSUTF8StringEncoding];

NSLog(@"Output: \n%@", outputString);
// (null or truncated) when stdout exceeds x amount of stdout

要测试功能,请在myExternalCommand的大文件上使用cat或类似工具。 这个问题似乎发生在 32759 字符长度之后......

解决方案? 我不确定,但可能需要发生的是以某种方式读取块中的返回stdout ,然后在可能的情况下附加outputString数据。

更新:我试着移动waitUntilExitreadDataToEndOfFile每建议,但它并没有影响结果。

*请注意,我正在寻找Obj-C解决方案,谢谢。

CocoaDev找到

“通过管道的数据被缓冲; 缓冲区的大小由底层操作系统决定。”

来自: http : //developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSPipe_Class/index.html

NSPipe 缓冲区限制似乎是 4096 字节(参见 /usr/include/limits.h: “... #define _POSIX_ARG_MAX 4096 ...”)

您可以从读取输出NSTask异步,使用readabilityHandler 在处理程序中,使用availableData逐个读取输出。

使用终止处理程序在任务退出后获得通知,然后将您的readabilityHandler设置为 nil 以阻止它读取。

这都是异步的,所以你需要阻塞并等待任务退出。

这是一个完整的示例,对我来说效果很好。 我使用printf而不是NSLog ,因为NSLog似乎正在截断控制台上的输出(不确定这是错误还是功能)。 错误检查被省略并增加了一些复杂性,您可能也希望以相同的方式读取standardError

dispatch_semaphore_t waitHandle;
NSTask *myTask;
NSMutableData* taskOutput;
        
waitHandle = dispatch_semaphore_create(0);
        
myTask = [[NSTask alloc] init];
[myTask setLaunchPath:@"/bin/cat"];
[myTask setArguments:[NSArray arrayWithObjects: @"/path/to/a/big/file", nil]];
[myTask setStandardOutput:[NSPipe pipe]];
        
taskOutput = [[NSMutableData alloc] init];
        
[[myTask.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
    NSData *data = [file availableData];
    [taskOutput appendData:data];
}];
        
[myTask setTerminationHandler:^(NSTask *task) {
    [task.standardOutput fileHandleForReading].readabilityHandler = nil;
            
    NSString *outputString = [[NSString alloc] initWithData:taskOutput encoding:NSUTF8StringEncoding];
    printf("Output: \n%s\n", [outputString UTF8String]);
            
    dispatch_semaphore_signal(waitHandle);
}];
        
[myTask launch];
        
dispatch_semaphore_wait(waitHandle, DISPATCH_TIME_FOREVER);

我有一个任务立即抛出一个大错误并导致挂起,向 stderr 添加一个读取器解决了这个问题

[[myTask.standardError fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
    NSData *data = [file availableData];
    [taskError appendData:data];
}];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM