2009-08-28 60 views
4

首先,讓我向SO社區道歉,告訴你一些本應該如此微不足道的事情。但是我一整天都在這裏,而且我已經走到了盡頭。同時使用緩衝讀取器讀取輸入和錯誤流掛起

我的程序中有一部分需要從輸入流中提取文本,並從使用Runtime.getrunTime()。exec()啓動的進程中引發錯誤流,並將其傳遞到標準輸入和輸出中有序推進。我有一個功能,我可以告訴應該工作。但它似乎陷入了一個捕獲22的地方,它正在等待該流報告就緒 - 但該流已經完成並且沒有報告。我很困惑。我想不出另一種適合我的限制的方法,而且我對這樣的catch-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結束時讀取的報告嗎?流程正在完成,所以他們的溪流應該快死了。我在這裏做錯了什麼?

回答

1

如果我沒有記錯,衍生進程將永遠不會關閉流 - 所以你需要有讀者在自己的線程,睡在主線程上,直到完成這個程序,然後關閉以饗讀者。

3

這是必要併發消耗2流,以防止堵塞。有關更多信息,請參閱this article,並特別注意StreamGobbler機制,它在單獨的線程中捕獲stdout/err。

6

有兩個更多的可能性:

  • 使用的ProcessBuilder並調用redirectErrorStream(true)加入兩個流,你需要讀取一個數據流。我有一個例子here
  • 在JDK7,你可以調用inheritIO()自動轉發一切

編輯關於第二個猜測,似乎準備()調用誤導你的程序。試試這個:

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中,如果你不打算任何額外的轉換:

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); 
}