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

相關問題