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

たぶん、記事で公開されているコードの行に沿ってNSPipeをフラッシュしてみてください。

「NSTasks、NSPipes、および読み取り時のデッドロック...」、

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

さらに別のアプローチでは、NSTaskとNSUnbufferedIOの使用をテストできます。

DonYacktmanによる本「CocoaProgramming」にいくつかのサンプルコードがあります。

# 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 に答える
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 に答える
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 に答える