2009-08-28 12 views
4

最初に、SOコミュニティに謝罪してください。しかし、私はこの一日中、私のロープの終わりにいます。BufferedReaderを同時に使用して入力ストリームとエラーストリームを読み取るハング

Runtime.getrunTime()。exec()を使用して起動されたプロセスからの入力ストリームとエラーストリームからテキストをプルする必要があるプログラムのセクションがあり、それを標準入力と出力に渡します。規則的な方法。私は私が知ることができるように近くに働くはずの機能を持っています。しかし、それはストリームが準備ができているのを待っているcatch-22に巻き込まれているようですが、ストリームは終了し、報告しません。私はうんざりしている。私は自分の制約に合ったこれを行う別の方法を考えることはできません。そのようなキャッチ22が存在することができると私はむしろ懐疑的です。ここで

は私のコードです:

private void forwardStreamtoStd(InputStream in, InputStream err) 
throws IOException { 
    int c = -1; 
    BufferedReader inReader = new BufferedReader(
     new InputStreamReader(in, "US-ASCII")); 
    BufferedReader errReader = new BufferedReader(
     new InputStreamReader(err, "US-ASCII")); 
    boolean inFinished = false, errFinished = false; 

    try { 
     System.out.println("Begin stream read loop..."); 
     while (!inFinished && !errFinished) { 
     if (!inFinished) { 
      while (inReader.ready()) { 
       if ((c = inReader.read()) == -1) { 
        inFinished = true; 
       } 
       else { 
        System.out.print((char) c); 
       } 
      } 
     } 

     if (!errFinished) { 
      while (errReader.ready()) { 
       if ((c = errReader.read()) == -1) { 
        errFinished = true; 
       } 
       else { 
        System.err.print((char) c); 
       } 
      } 
     } 
     } 
     System.out.println("End stream read loop."); 
    } 
    catch (IOException e) { 
     throw e; 
    } 
    finally { 
     errReader.close(); 
     inReader.close(); 
    } 
} 

問題が読み取りループはストリームの準備ができて報告することを待っている、そしてその結果として-1を告げる読み取りによって返さ見ていないということのようですそれは終了する時間です。私はどちらかのストリームをブロックすることを避けようとしているので、準備が整ったら順番に両方から引き出すことができます。しかし、プロセスの終わりをどうやって捕まえることができますか?何か不足していますか?それがストリーム-1の終わりを持っているときに読み込まれたというレポートを読んではいけませんか?プロセスは終了しているので、ストリームが死んでいるはずです。私はここで間違って何をしていますか?

答えて

4

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4090471

私はいつも使用してきたソリューションは、プロセスのwaitForそして、ストリームの1つを読むために別のスレッドを作成し、メインスレッドが読み終えたときに、スレッドに参加する、としています。

1

私が正しく覚えていれば、生成されたプロセスはストリームを決して閉じることはないので、独自のスレッドに読者を置いて、プロセスが完了するまでメインスレッドでスリープしてから読者を閉じなければなりません。

3

必須ブロックを防ぐために、2つのストリームを同時に消費することが必要です。詳細については、this articleを参照してください。特に、stdout/errを別のスレッドで取得するメカニズムStreamGobblerに注意してください。

6

は、さらに2つの可能性があります。

  • は、2つのストリームを結合するためにredirectErrorStream(true)をProcessBuilderをを使用して起動すると、あなたは、1つのストリームを読み込む必要があります。私は例hereを持っています。 JDK7で
  • 2番目の推測で

編集自動的に転送すべてにinheritIO()を呼び出すことができ、準備ができて()の呼び出しは、あなたのプログラムを誤解されるようです。これを試してみてください:

private void createReader(final InputStream in, final OutputStream out) { 
    new Thread() { 
     public void run() { 
      try { 
       int c = 0; 
       while ((c = in.read()) != -1) { 
        out.write(c); 
       } 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } finally { 
       in.close(); 
      } 
     } 
    }.start(); 
} 
private void forwardStreamtoStd(InputStream in, InputStream err) 
throws IOException { 
    createReader(in, System.out); 
    createReader(err, System.err); 
} 
:あなたは余分な変換を計画していない場合

private void forwardStreamtoStd(InputStream in, InputStream err) 
throws IOException { 
    int c = -1; 
    BufferedReader inReader = new BufferedReader(
     new InputStreamReader(in, "US-ASCII")); 
    BufferedReader errReader = new BufferedReader(
     new InputStreamReader(err, "US-ASCII")); 
    boolean inFinished = false, errFinished = false; 

    try { 
     System.out.println("Begin stream read loop..."); 
     if (!inFinished) { 
      while ((c = inReader.read()) != -1) { 
        System.out.print((char) c); 
      } 
      inFinished = true; 
     } 

     if (!errFinished) { 
      while ((c = errReader.read()) != -1) { 
       System.err.print((char) c); 
      } 
      errFinished = true; 
     } 
     System.out.println("End stream read loop."); 
    } 
    catch (IOException e) { 
     throw e; 
    } 
    finally { 
     errReader.close(); 
     inReader.close(); 
    } 
} 

いっそは、BufferedReaderのをオフのままに

関連する問題