2012-02-06 21 views
2

Javaのプログラムを書いているので、WindowsやLinuxで実行できる必要があり、dirやlsなどのコマンドラインに要求を出す必要があります。次に、これらのコマンドから結果の出力を得る必要があり、AFTERWARDSは別のコマンドを求めるプロンプトを出します。ここに私のコードは次のとおりです。Javaのコマンドライン(マルチスレッド)

import java.io.*; 
import java.util.*; 

public class myShell 
{ 
    public static void main(String[] args) 
    { 
     Runtime runtime = Runtime.getRuntime(); 
     Process process; 
     Scanner keyboard = new Scanner(System.in); 
     String userInput = ""; 
     String osName = System.getProperty("os.name"); 
     BufferedReader brStdOut = null; 
     String stdOut; 
     BufferedReader brErrorStream = null; 
     String errorStream; 

     while(userInput.compareToIgnoreCase("exit") != 0) 
     { 
      System.out.println(); 
      System.out.print("??"); 

      userInput = keyboard.nextLine(); 

      int indexOfPound = userInput.indexOf('#'); 
      if(indexOfPound == 0) 
      { 
       userInput = ""; 
      } 
      else if(indexOfPound > 0) 
      { 
       userInput = userInput.substring(0, indexOfPound); 
      } 
      userInput = userInput.trim(); 

      try 
      { 
       if(osName.contains("Windows")) 
       { 
        process = runtime.exec("cmd /c " + userInput); 
       } 
       else 
       { 
        process = runtime.exec(userInput); 
       } 

       brStdOut = new BufferedReader(new InputStreamReader(
          process.getInputStream())); 
       brErrorStream = new BufferedReader(new InputStreamReader(
           process.getErrorStream())); 

       while((stdOut = brStdOut.readLine()) != null) 
       { 
        System.out.println(stdOut); 
       } 
       while((errorStream = brErrorStream.readLine()) != null) 
       { 
        System.err.println(errorStream); 
       } 

       process.waitFor(); 
      } 
      catch(Exception e) 
      { 
       System.out.println("Error executing: " + userInput); 
       System.out.println(e.getMessage()); 
      } 
      try 
      { 
       brStdOut.close(); 
      } 
      catch(Exception e) 
      { 
      } 
      try 
      { 
       brErrorStream.close(); 
      } 
      catch(Exception e) 
      { 
      } 
     } 
     System.exit(0); 
    } 
} 

私は現在、Windows 7マシンでのテストと行の#の後に何をコメントとしてみなされていることだと言及する必要があります。

これを実行すると、dirを使用しても結果は正常ですが、ls(Windowsでは認識されていないコマンドであることを示すメッセージが表示されます)を実行してみてください。次のプロンプトの後、または部分的にプロンプ​​トの後に、プロンプトの後に部分的に表示されます。プロンプトの前にエラーメッセージの印刷を一貫して行う方法はありますか?ここで

は今何が起こっているかの例です:私は、日付などのコマンドを実行してみたときに

??dir 
Volume in drive C is Windows7_OS 
Volume Serial Number is SomeNumbers 

Directory of C:\Users\BlankedOut\Documents\Java\Eclipse\Workspace\Prog1 

02/05/2012 03:48 PM <DIR>   . 
02/05/2012 03:48 PM <DIR>   .. 
02/05/2012 03:48 PM    301 .classpath 
02/05/2012 03:48 PM    387 .project 
02/05/2012 03:48 PM <DIR>   .settings 
02/05/2012 08:39 PM <DIR>   bin 
02/05/2012 08:39 PM <DIR>   src 
       2 File(s)   688 bytes 
       5 Dir(s) 861,635,362,816 bytes free 

??ls 

??'ls' is not recognized as an internal or external command, 
operable program or batch file. 
ls 
'ls' is not recognized as an internal or external command, 
operable program or batch file. 

??exit 

私の他の質問を考えています。 DOSウィンドウでは、これは2行の応答を返し、さらに多くの入力を待ちますが、Javaでは応答の最初の行だけを取得します(ただし、dirはすべての行を取得するようですが)ラインは、プログラムがちょうどハングする...誰がなぜこれが起こっているかもしれないか知っていますか?

ありがとうございます!そのため上記のコードブロックの

答えて

1

あなたはLSを実行すると、そこにエラーがあると、エラーが両方の標準出力に、エラーストリームに示されることになる、

   while((stdOut = brStdOut.readLine()) != null) 
       { 
        System.out.println(stdOut); 
       } 
       while((errorStream = brErrorStream.readLine()) != null) 
       { 
        System.err.println(errorStream); 
       } 

は、エラーは常に、STDアウト後に印刷されていますあなたは望ましい出力を得るためにループを切り替えることができます。

日付プロンプトでは、プロンプトがユーザー入力を待つ新しい日付を尋ねます。あなたのプログラムが何も与えていないところで、それはそこで待っています。

編集:これは()出力とエラーの両方のストリームをフラッシュすることを確認し、正しい順序で常に出力を取得するには、別のスレッド、

import java.lang.*; 
import java.io.*; 

public class StreamGobbler implements Runnable { 
    String name; 
    InputStream is; 
    Thread thread; 
    String output=""; 

    public StreamGobbler (String name, InputStream is) { 
    this.name = name; 
    this.is = is; 
    } 

    public void start() { 
    thread = new Thread (this); 
    thread.start(); 
    } 

    public void run() { 
    try { 
    InputStreamReader isr = new InputStreamReader (is); 
    BufferedReader br = new BufferedReader (isr); 

     while (true) { 
      String s = br.readLine(); 
      if (s == null) break; 
      output += s; 
     } 
     is.close(); 
     } catch (Exception ex) { 
      System.out.println ("Problem reading stream " + name + "... :" + ex); 
     ex.printStackTrace(); 
     } 
    } 
} 

    public class ProgA { 
    public static void main(String[] args) throws Exception { 
    Runtime rt = Runtime.getRuntime(); 
    Process p = rt.exec("execute command prompt"); 
    StreamGobbler s1 = new StreamGobbler ("stdin", p.getInputStream()); 
    StreamGobbler s2 = new StreamGobbler ("stderr", p.getErrorStream()); 
    s1.start(); 
    s2.start(); 
    p.waitFor(); 
    System.out.println(s2.output + s1.output); 
    } 
    } 
+0

おそらくdirコマンドにエラーがないので、デバッグして何が起こっているのかを確認してください。 –

+0

whileループの順序を単純に切り替えようとしました。その結果、私がdirを実行しようとすると、出力は生成されず、プログラムはただ停止してしまいました。これは、プロンプトがまだ出力ストリームを基準にしてどこでも印刷できるという事実を修正しませんでした。私は2つのブロックを組み合わせることが助けになると思っていましたが(次のポストはありません)、これはブロックの順序を切り替えるのと同じ問題を抱えていました... –

+0

答えにスレッドを追加しました。 –

1

を使用するよう、これを試してみてください。

dateコマンドについて
System.err.flush(); //after writing to error stream and 
System.out.flush(); //after writing to output stream 

あなたが次の操作を行うことができますので、それがユーザーの入力を期待:

process.getOutputStream().close(); // after runtime.exec 
0

それがいっぱいになった場合は、それが実行されている場合、プロセスからの出力を読み取るために、別のスレッドを使用する必要があります。親/子プロセス間のバッファーは基本的にハングします。これはWindows XPの大きな問題でした。バッファーは小さく、すぐに別のスレッドを開始しなければ、プロセスは死んでしまいました。これは、あなたのコメントで言及したようにエラー/ stdoutの読者を入れ替えたときにあなたのプログラムがハングした理由です。

私はWindows 7を試していないので、より良いかもしれません。

また、出力ストリームとエラーストリームをマージするためにJavaのオプションを使用すると便利です。そうすれば、2つのスレッドを起動する必要はありません。