0

我知道这已经被问到过,但是,有时人们会碰到其他答案似乎没有帮助。如何在我的Java应用程序中与C控制台应用程序进行交互

我需要启动一个C应用程序,并通过它的几个输入来浏览其菜单,以最终执行我所需要的。最终的输出(结果)被发送到一个文件,但是中间输出(控制台上打印的菜单和子菜单)很适合打印在我的Eclipse控制台上进行调试。

我根据用户Vince posted on his question和后面提到的工作编写了下面的代码,但它似乎没有为我做。

public final class InteractWithExternalApp { 

    private static PrintWriter printOut; 
    private static BufferedReader retrieveOutput; 

    private static Process p; 

    private EvaluationTests(){} // suppressing the class constructor 

    public static void Evaluate(String paramToApp) { 
     try 
     { 
      Runtime rt = Runtime.getRuntime() ; 
      p = rt.exec("C:\\Path\\To\\Desktop\\appName " + paramToApp); 
      InputStream in = p.getInputStream() ; 
      OutputStream out = p.getOutputStream(); 

      retrieveOutput = new BufferedReader(new InputStreamReader(in)); 
      printOut = new PrintWriter(out); 

      // print menu 
      if((line = retrieveOutput.readLine()) != null) { 
      System.out.println(line); 
      } 

      // send the input choice -> 0 
      printOut.println("0"); 
      printOut.flush(); 

      // print sub-menu 
      if((line = retrieveOutput.readLine()) != null) { 
       System.out.println(line); 
      } 

      // send the input choice 
      printOut.println("A string"); 
      printOut.flush(); 

      // print sub-menu 
      if((line = retrieveOutput.readLine()) != null) { 
       System.out.println(line); 
      } 

      /* 
       Repeat this a few more times for all sub-menu options until 
       the app finally executes what's needed 
      */ 

     }catch(Exception exc){ 
      System.out.println("Err " + exc.getMessage()); 
     } 

     return; 
    } 

而且,作为一个练习,我试图打开Windows命令提示符并发送一个命令,下面给出here的例子。 cmd.exe打开罚款,但然后通过一个echo命令没有做任何事情。

OutputStream stdin = p.getOutputStream(); 
InputStream stdout = p.getInputStream(); 

stdin.write(new String("echo test").getBytes()); 
stdin.flush(); 

有人能请一下吗?我哪里错了?

+0

。请使用ProcessBuilder。它更好地处理白色空间。 – Jayan 2014-11-01 05:28:57

+0

@Jayan,你的意思是在'ProcessBuilder pb = new ProcessBuilder(“C:\\ Path \\ To \\ Desktop \\ appName”,“paramToApp”);''和'pb.start()'? 既然你没有正式回答这个问题,我应该猜测这是唯一的问题,其余的将会很好地工作或者只是一个改进? – 2014-11-01 06:38:21

+0

是的。那将是一个开始。 – Jayan 2014-11-01 07:39:40

回答

2

我不想说我是100%正面,但我99%确信问题在于Java和C程序的输入和输出流之间的连接。我能够启动程序,但无法传递我需要的参数。

解决方案的确使用ProcessBuilder。感谢您鼓励我回到之前我找到的解决方案,@Jayan。

因此,这里的最终代码:

public final class InteractWithExternalApp { 

private static BufferedReader inputReader, errorReader; 
private static OutputStream outputStream; 
private static PrintStream printOutputStream; 

private InteractWithExternalApp(){} // suppressing the class constructor 

public static void Evaluate(String paramToApp) { 
    System.out.println("Running evaluation tests..."); 

    try 
    { 
     ProcessBuilder pb = new ProcessBuilder("Path/to/my/C/application", "paramToApp"); 
     pb.redirectOutput(Redirect.INHERIT); 
     pb.redirectError(Redirect.INHERIT); 
     Process process = pb.start(); 

     String line; 

     errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 
     while((line = errorReader.readLine()) != null){ 
      System.out.println(line); 
     } 

     inputReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 
     while((line = errorReader.readLine()) != null){ 
      System.out.println(line); 
     } 

     outputStream = process.getOutputStream(); 
     printOutputStream = new PrintStream(outputStream); 
     printOutputStream.println("A parameter"); printOutputStream.flush(); 
     printOutputStream.println("Another parameter"); printOutputStream.flush(); 
     printOutputStream.println("And however many more I would need to finally get where I wanted"); printOutputStream.flush(); 

     inputReader.close(); 
     errorReader.close(); 
     printOutputStream.close(); 

    } catch(IOException ioe){ 
     System.out.println("Error during evaluation routine: " + ioe.getMessage()); 
    } finally { 
     System.out.println("Evaluation complete!"); 
    } 

    return; 
} 

因为我还没有足够的声誉“投了”的回答,我在这里正式表达我的感谢@Benjamin Gruenbaum和@samaitra,谁张贴他们的答案this question,我从那里得到解决方案。

我希望这可以帮助其他人。

0

这是与readLine()挂在它的末尾没有“\ n”时挂起的问题.... 有很多方法来剥皮这只猫,但这是最简单的恕我直言(高性能)... 使用nio CharBuffer代替readLine(),它(read(CharBuffer))会很满意在最后丢失换行符,并且可能会捕获所需的所有内容。如果您知道您的应用会在中间暂停,请根据需要添加一些Thread.sleep()调用,以确保您获得了一切。细心的意见均显示

代码包装是可读性不必要的冗长,倒塌需要:
Thread.sleep(1000) //sleep for a sec to make sure the app started outputting
final CharBuffer cb = CharBuffer.allocate(1024 * 1024); // I set a 1mb for the buffer, but it's probably excessive boolean canPrint = true; // print menu String data; while (canPrint) { if (retrieveOutput.ready()) { cb.clear(); if (retrieveOutput.read(cb) != -1) { cb.flip(); data = cb.toString(); cb.flip(); final String[] params = data.split("\n"); //split the output back into lines (not really needed) for (final String line : params) { LOG.info(line.replace("\r", "")); // these will be there on windows but not Unix or OSX } Thread.sleep(1000) //sleep for a sec to see if more output will be added } else { canPrint = false; } } else { canPrint = false; } }

HTH,

+0

嗨,@ nrapopor。让我直截了当地说明:你建议的代码应该代替我所说的“打印菜单”和“打印子菜单”的每一个实例吗? – 2014-11-03 01:20:48

+0

谢谢你的努力,@ nrapopor。我发布了答案,也许你想看看! – 2014-11-03 05:23:26

相关问题