[英]Objective-C, NSTask Buffer Limitation
I'm using NSTask
to run an external utility which returns a long string of data.我正在使用
NSTask
运行一个返回一长串数据的外部实用程序。 The problem is that when the returned string exceeds a large amount of data (around 32759 chars) it becomes null
or truncates the returned string.问题在于,当返回的字符串超过大量数据(大约 32759 个字符)时,它会变为
null
或截断返回的字符串。 How do I return the full output?如何返回完整输出?
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
To test the functionality use cat
or similar on a large file for the myExternalCommand
.要测试功能,请在
myExternalCommand
的大文件上使用cat
或类似工具。 The issue seems to happen right after the character length of 32759...这个问题似乎发生在 32759 字符长度之后......
solution?解决方案? I'm not sure, but what might need to happen is to somehow read the return
stdout
in chunks, then append the outputString
data if possible.我不确定,但可能需要发生的是以某种方式读取块中的返回
stdout
,然后在可能的情况下附加outputString
数据。
update: I tried moving waitUntilExit
after readDataToEndOfFile
per suggestion, but it did not affect the outcome.更新:我试着移动
waitUntilExit
后readDataToEndOfFile
每建议,但它并没有影响结果。
*please note, I'm looking for an
Obj-C
solution, thanks.*请注意,我正在寻找
Obj-C
解决方案,谢谢。
Found on CocoaDev :在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
来自: 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 …”)
NSPipe 缓冲区限制似乎是 4096 字节(参见 /usr/include/limits.h: “... #define _POSIX_ARG_MAX 4096 ...”)
You can read the output from your NSTask
asynchronously, using readabilityHandler .您可以从读取输出
NSTask
异步,使用readabilityHandler 。 Within the handler, use availableData
to read the output piece-by-piece.在处理程序中,使用
availableData
逐个读取输出。
Use a terminationHandler to get notified once the task exits, and then set your readabilityHandler
to nil to stop it from reading.使用终止处理程序在任务退出后获得通知,然后将您的
readabilityHandler
设置为 nil 以阻止它读取。
It's all async, so you'll need to block and wait until the task exits.这都是异步的,所以你需要阻塞并等待任务退出。
Here is a complete sample that works well enough for me.这是一个完整的示例,对我来说效果很好。 I used a
printf
instead of NSLog
as it seems that NSLog
is truncating the output on the console (not sure if that's a bug or a feature ).我使用
printf
而不是NSLog
,因为NSLog
似乎正在截断控制台上的输出(不确定这是错误还是功能)。 Error checking is omitted and adds some complexity, you will probably want to read standardError
as well in the same way.错误检查被省略并增加了一些复杂性,您可能也希望以相同的方式读取
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);
I had a task that was throwing a large error immediately, and causing a hang, adding a reader to the stderr solved the issue我有一个任务立即抛出一个大错误并导致挂起,向 stderr 添加一个读取器解决了这个问题
[[myTask.standardError fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
NSData *data = [file availableData];
[taskError appendData:data];
}];
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.