【问题标题】:NSTask with long output (OSX)具有长输出的 NSTask (OSX)
【发布时间】:2013-05-30 14:49:29
【问题描述】:

我一直在寻找答案很长时间,但我从来没有得到一个有效的代码。

我有一个使用 dd 生成文件的代码。有时需要几分钟,具体取决于大小,我认为有一个进度条会很棒。到目前为止,一切正常并已绑定。但是,进度条不会更新,因为我需要不断地向它发送值。我找到了一种获取当前值的方法,我设法让 pv 显示当前数据,但现在我无法在应用程序内部实时获取输出,除了在日志中。

到目前为止,这是我能做到的最好的:

// Action:
// dd if=/dev/zero bs=1048576 count=500 |pv -Wn -s <size>|of=/Users/me/Desktop/asd.img
// Be careful, it generates files of 500MB!!

NSTask * d1Task = [[NSTask alloc] init];
NSTask * pvTask = [[NSTask alloc] init];
NSTask * d2Task = [[NSTask alloc] init];

[d1Task setLaunchPath:@"/bin/dd"];
[pvTask setLaunchPath:@"/Users/me/Desktop/pv"];
[d2Task setLaunchPath:@"/bin/dd"];

// For pvTask I use  something like...
// [[NSBundle mainBundle] pathForAuxiliaryExecutable: @"pv"]
// ... in the final version.

[d1Task setArguments: [NSArray arrayWithObjects:
                         @"if=/dev/zero"
                       , @"bs=1048576"
                       , @"count=500"
                       , nil]];

[pvTask setArguments:[NSArray arrayWithObjects:
                        @"-Wn"
                      , [ NSString stringWithFormat:@"-s %d", 1048576 * 500]
                      , nil]];

[d2Task setArguments: [NSArray arrayWithObjects:
                        @"of=/Users/me/Desktop/file.dmg"
                      , nil]];

NSPipe * pipeBetween1 = [NSPipe pipe];
[d1Task setStandardOutput: pipeBetween1];
[pvTask setStandardInput: pipeBetween1];

NSPipe * pipeBetween2 = [NSPipe pipe];
[pvTask setStandardOutput: pipeBetween2];
[d2Task setStandardInput: pipeBetween2];

// Missing code here

[d1Task launch];
[pvTask launch];
[d2Task launch];

在缺少的代码部分,我尝试了几件事。首先我尝试了一个观察者,像这样:

NSFileHandle * pvOutput = [pipeBetween2 fileHandleForReading];
[pvOutput readInBackgroundAndNotify];

[ [NSNotificationCenter defaultCenter]
     addObserver:self
        selector:@selector(outputData:)
            name:NSFileHandleDataAvailableNotification
          object:pvOutput
];

没有成功。我只在执行开始或结束时收到反馈,但在执行过程中仍然没有反馈。

我也尝试过类似的方法:

[pvOutput setReadabilityHandler:^(NSFileHandle *file) {
// Stuff here
}];

但是这里没有这样的方法。也许我的 XCode 已经过时了? (我用的是 4.2)。

最近我一直在尝试使用 /sbin/ping ping 服务器 10 次相同的通用代码,但没有成功获得输出。我怎样才能做到这一点?我可以阅读有关此主题的任何文件吗?

谢谢!

【问题讨论】:

  • 不确定这是否是正确的解决方案。但是在后台线程中运行你的任务怎么样?
  • 嗨 Martin,pv 是一个管道查看器。请参考本页:catonmat.net/blog/unix-utilities-pipe-viewer
  • 嗨 Mikael,我也尝试使用 Grand Central Dispatch。我的原始代码使用 GCD。这是一个辅助项目,用于测试观察者或任何其他从 dd 和 pv 获取反馈的方法。
  • dd 所做的只是复制数据。你可以在没有NSTask 的情况下自己做得更好,并且你可以完全访问进度而无需进行黑客攻击。
  • 嗨 trojanfoe,我有这个代码是因为之前的问题我不得不生成大的空白文件而没有内存问题.. 你可以检查我之前做的一个与此相关的问题 这里:stackoverflow.com/questions/8874757/…

标签: objective-c macos cocoa xcode4.2


【解决方案1】:

pv 工具将进度输出写入标准错误,因此您应该建立 另一个管道:

NSPipe *pvStderrPipe = [NSPipe pipe];
[pvTask setStandardError:pvStderrPipe];
NSFileHandle *pvError = [pvStderrPipe fileHandleForReading];

[pvError waitForDataInBackgroundAndNotify];
[[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
                          object:pvError queue:nil
                          usingBlock:^(NSNotification *note) 
{
     NSData *progressData = [pvError availableData];
     NSString *progressStr = [[NSString alloc] initWithData:progressData encoding:NSUTF8StringEncoding];
     NSLog(@"progress: %@", progressStr);

     [pvError waitForDataInBackgroundAndNotify];
 }];

一个完全不同的解决方案可能是使用“dd”的以下特性:

如果 dd 收到一个 SIGINFO 信号, 当前输入和输出块计数将被写入 与标准完成格式相同的标准错误输出 消息。

因此您可以将管道连接到“dd”的标准错误并调用

kill([ddTask processIdentifier], SIGINFO);

定期。那么你就不需要“pv”,可能只需要一个“dd”任务。

【讨论】:

  • 如果我使用setStandardError¿¿¿¿... 的日志很长,观察者仍然没有得到更新。不过,我会尝试第二个建议,我很感激!
  • 到目前为止,kill 似乎没有做任何事情,我会检查文档。我确实喜欢这样:while ([ddTask isRunning]) { kill([ddTask processIdentifier], SIGINFO); }。文件生成正常,没有输出。
  • @Apollo:我添加了更多在我的测试应用程序中工作的示例代码。 - 第二种解决方案只是一个想法。你必须使用计时器,一个简单的while循环不能工作,因为程序控制永远不会返回到主runloop。
  • @Apollo:不客气。 - 但请注意,特洛伊木马在他的评论中提出了一个有效的观点。从一个文件读取块并将它们写入另一个文件的简单循环应该很容易实现(例如使用 NSFileHandle)并且可能更有效。
猜你喜欢
  • 1970-01-01
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多