簡體   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