Objective-C,NSTask 缓冲区限制
Objective-C, NSTask Buffer Limitation
我正在使用 NSTask
到 运行 一个外部实用程序,其中 return 是一长串数据。问题是,当 returned 字符串超过大量数据(大约 32759 个字符)时,它变成 null
或 t运行cates returned 字符串。我如何 return 完整输出?
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 之后...
解决方案?我不确定,但可能需要以某种方式分块读取 return stdout
,然后尽可能附加 outputString
数据。
更新:我尝试根据建议将 waitUntilExit
移动到 readDataToEndOfFile
之后,但这并没有影响结果。
*please note, I'm looking for an Obj-C
solution, thanks.
发现于 CocoaDev:
“The data that passes through the pipe is buffered; the size of the buffer is determined by the underlying operating system.”
from: http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSPipe_Class/index.html
The NSPipe buffer limit seems to be 4096 bytes (cf. /usr/include/limits.h: “… #define _POSIX_ARG_MAX 4096 …”)
您可以使用 readabilityHandler 异步读取 NSTask
的输出。在处理程序中,使用 availableData
逐个读取输出。
使用 terminationHandler 在任务退出后得到通知,然后将 readabilityHandler
设置为 nil 以停止读取。
都是异步的,所以你需要阻塞等待任务退出。
这是一个完整的示例,对我来说效果很好。我使用 printf
而不是 NSLog
,因为看起来 NSLog
正在截断控制台上的输出(不确定那是否是 bug or a feature)。省略了错误检查并增加了一些复杂性,您可能也想以相同的方式阅读 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 添加 reader 解决了这个问题
[[myTask.standardError fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
NSData *data = [file availableData];
[taskError appendData:data];
}];
我正在使用 NSTask
到 运行 一个外部实用程序,其中 return 是一长串数据。问题是,当 returned 字符串超过大量数据(大约 32759 个字符)时,它变成 null
或 t运行cates returned 字符串。我如何 return 完整输出?
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 之后...
解决方案?我不确定,但可能需要以某种方式分块读取 return stdout
,然后尽可能附加 outputString
数据。
更新:我尝试根据建议将 waitUntilExit
移动到 readDataToEndOfFile
之后,但这并没有影响结果。
*please note, I'm looking for an
Obj-C
solution, thanks.
发现于 CocoaDev:
“The data that passes through the pipe is buffered; the size of the buffer is determined by the underlying operating system.”
from: http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSPipe_Class/index.html
The NSPipe buffer limit seems to be 4096 bytes (cf. /usr/include/limits.h: “… #define _POSIX_ARG_MAX 4096 …”)
您可以使用 readabilityHandler 异步读取 NSTask
的输出。在处理程序中,使用 availableData
逐个读取输出。
使用 terminationHandler 在任务退出后得到通知,然后将 readabilityHandler
设置为 nil 以停止读取。
都是异步的,所以你需要阻塞等待任务退出。
这是一个完整的示例,对我来说效果很好。我使用 printf
而不是 NSLog
,因为看起来 NSLog
正在截断控制台上的输出(不确定那是否是 bug or a feature)。省略了错误检查并增加了一些复杂性,您可能也想以相同的方式阅读 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 添加 reader 解决了这个问题
[[myTask.standardError fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
NSData *data = [file availableData];
[taskError appendData:data];
}];