【问题标题】:Code problem - objective c - waiting for string value to appear in string value代码问题-目标c-等待字符串值出现在字符串值中
【发布时间】:2010-08-13 12:33:53
【问题描述】:
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

【问题讨论】:

    标签: objective-c nsstring nsdata nstask


    【解决方案1】:

    Elijah,将您的代码编辑成如下所示:

    ...
    [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>" 出现后终止任务找到了,所以它不会一直运行)。

    【讨论】:

    • 呸!不,它仍然在 while 循环中冻结。我在我的问题中发布了我当前的代码。有什么想法吗?
    • 另外,就像我之前说的:似乎,当我在 while 循环之前检查输出字符串是什么时,我得到“正在启动程序 G”,这是 .sh 文件中的一个回显,以澄清这一点它开始了。但是,在while循环中,我检查了输出字符串的值,它返回了同样的东西......没有其他设置......只是回声。我正在用 NSRunAlertPanel() 检查它
    • 除了原始的echo,您的 bash 文件还如何打印到标准输出?还有其他应该运行的echo 吗?从终端运行 bash 文件时的输出是什么?用户应该输入任何输入吗?
    • 嗯,它是 ALICE AI 的 java AIML 解释器。我想为它制作一个 GUI。 Server.sh 只是运行机器人。而且,是的,有用户输入。我猜它除了 echo 没有输出任何其他东西,因为其他东西已经设置好了。好吧,直到它有一行用于机器人的响应和用户输入(全部通过终端运行)
    • 嗯,当然它没有打印任何东西。如果 bash 文件的其余部分只是设置,它不会打印任何内容。能否请您发布 bash 文件,以便我查看您是如何运行它的?如果您希望运行这样的程序,尤其是通过 GUI...,您将不得不设置多个 NSTasks
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      "NSTasks, NSPipes, and deadlocks when reading...",

      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];
      

      【讨论】:

        【解决方案4】:

        对于 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
        ...
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-07
          • 2017-06-27
          • 1970-01-01
          • 1970-01-01
          • 2019-07-14
          相关资源
          最近更新 更多