1
task = [NSTask new];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObject:@"/applications/jarvis/brain/server.sh"]];
[task setCurrentDirectoryPath:@"/"];

NSPipe *outputPipe = [NSPipe pipe];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput:outputPipe];

[task launch];

NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]];
     }

NSArray* substrings = [outputString componentsSeparatedByString:@"Jarvis>"];
NSString* finalCharlieOutputNSTask = [substrings lastObject];
NSSpeechSynthesizer * syn = [[NSSpeechSynthesizer alloc] init];
[syn startSpeakingString:finalCharlieOutputNSTask]; 
self.charlieOutput.stringValue = finalCharlieOutputNSTask;

好的,这就是我的代码。它启动一个 SH 文件并读取输出。但是,我希望它等到“Jarvis>”出现在字符串中,然后再说出并打印结果。但是,似乎在 while 循环中,我的代码在那里冻结了。没有它,它会读取启动 server.sh 文件的正常输出,但会读取整个内容。任何想法为什么这不起作用?

这是 Server.sh 文件:

echo Starting Jarvis Program D.
ALICE_HOME=.
SERVLET_LIB=lib/servlet.jar
ALICE_LIB=lib/aliceserver.jar
JS_LIB=lib/js.jar

# Set SQL_LIB to the location of your database driver.
SQL_LIB=lib/mysql_comp.jar

# These are for Jetty; you will want to change these if you are using a different http server.
 HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar

 PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
 java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
4

4 回答 4

1

您想将 readDataToEndOfFile 放入循环中。否则,它会读取一次数据,检查您的字符串是否存在,如果在第一次读取中没有找到它,则永远循环。

于 2010-08-13T12:36:50.993 回答
1

以利亚,编辑您的代码,使其看起来像这样:

...
[task launch];

NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
    [outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease];
}

if ([task isRunning]) {
    [task terminate];
}

NSArray *subStrings = [outputString componentsSeparatedByString:@"Jarvis>"];
...

循环中的这段代码将依次从你的文件中读取输出数据并将其附加到当前输出中,并在找到@"Jarvis>" 时停止读取(它也会在找到@"Jarvis>" 后终止任务,所以它不会永远运行)。

于 2010-08-13T14:07:34.940 回答
1

也许尝试按照文章中发布的代码行刷新 NSPipe:

"阅读时的 NSTasks、NSPipes 和死锁...",

http://dev.notoptimal.net/2007/04/nstasks-nspipes-and-deadlocks-when.html

另一种方法可以测试 NSTask 和 NSUnbufferedIO 的使用。

您将在 Don Yacktman 的“Cocoa Programming”一书中找到一些示例代码。

# http://www.cocoaprogramming.net
# http://www.cocoaprogramming.net/CocoaProgramming-20021010.tgz

open -e CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.h \
        CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.m \
        CocoaProgramming-20021010/Chapter\ 24/Calendar/CalendarController.m

# for yet another try with sample code using waitForDataInBackgroundAndNotify see:
# http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html

open -e OpenFileKiller/NSTask+OneLineTasksWithOutput.m
# --> [standardOutputFile waitForDataInBackgroundAndNotify];
于 2010-08-17T08:35:37.443 回答
0

对于 NSTask 和 NSFileManager 的非阻塞 IO 代码,请参见 DOCtor 的源代码:

# http://www.stone.com/DOCtor/
# http://www.stone.com/DOCtor/DOCtor.tar.gz

open -e DOCTor/NSFileHandle_CFRNonBlockingIO.h \
        DOCTor/NSFileHandle_CFRNonBlockingIO.m \
        DOCTor/NSFileManager-Extensions.h \
        DOCTor/NSFileManager-Extensions.m

另请注意,如果 stdout 是管道而不是交互式终端 (tty),许多命令行程序(内部)将其输出缓存到 stdout。出于这个原因,一些命令行程序有特殊的选项来对它们的输出进行行缓冲,而不管将输出发送到管道或 tty。

tcpdump -l
grep --line-buffered
...
于 2010-08-17T21:06:58.420 回答