ios - Objective-C,NSTask 缓冲区限制
问题描述
我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
要cat
在myExternalCommand
. 该问题似乎发生在 32759 字符长度之后...
解决方案?我不确定,但可能需要以某种方式以块的形式读取返回,然后 尽可能stdout
附加数据。outputString
更新:我根据建议尝试移动waitUntilExit
,readDataToEndOfFile
但不影响结果。
*请注意,我正在寻找
Obj-C
解决方案,谢谢。
解决方案
在CocoaDev上找到:
“通过管道的数据被缓冲;缓冲区的大小由底层操作系统决定。”</p>
来自:http: //developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSPipe_Class/index.html
NSPipe 缓冲区限制似乎是 4096 字节(参见 /usr/include/limits.h:“... #define _POSIX_ARG_MAX 4096 ...”)
您可以使用readabilityHandlerNSTask
异步读取输出。在处理程序中,用于逐个读取输出。availableData
一旦任务退出,使用终止处理程序获得通知,然后将您的设置readabilityHandler
为 nil 以停止读取。
这都是异步的,因此您需要阻止并等待任务退出。
这是一个对我来说足够好用的完整示例。我使用 aprintf
而不是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);