[英]ProcessBuilder: Forwarding stdout and stderr of started processes without blocking the main thread
[英]Processbuilder without redirecting StdOut
是否可以將輸出流重定向回進程,或者根本不重定向?
背景故事:我正在嘗試使用 processbuilder 啟動一個可執行文件。 (准確地說是源專用服務器/srcds.exe)
使用 processbuilder 啟動它的結果是,此可執行文件的控制台窗口保持為空。 啟動幾秒鍾后,可執行文件崩潰並顯示錯誤“CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents”,因為它的控制台是空的。
我認為您正在談論使啟動的進程的標准輸出轉到當前進程的標准輸出。 如果您使用的是 JDK7,那就很簡單:
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
更新:(太多評論)我認為你很困惑。 當您從終端啟動進程時,該進程成為該終端進程的子進程,並且標准輸出被發送到該終端。 當您從 Java 啟動一個進程時,該進程是 Java 進程的子進程,並且其標准輸出轉到 Java。
在第一種情況下,有一個終端顯示 stdout,因為您自己從終端啟動了它,這就是終端對 stdout 所做的。 但是,當從 Java 啟動時,不會有終端窗口,除非您啟動的進程中的某些內容打開了終端,並且您啟動的進程的 stdout 被交還給您,程序員,您可以隨意處理。 從終端啟動時所看到的等效行為是我已經提到的Redirect.INHERIT
。
您現在的問題不是 Java。 你的問題是不明白這個“srcds.exe”期望如何處理標准輸入和標准輸出。 弄清楚這一點,然后回來詢問如何用 Java 做到這一點。
我現在只是猜測,但您可以嘗試從進程的標准輸出中讀取並將其反饋到標准輸入中。 也許這就是它所期待的? 不過,這聽起來很瘋狂。
你可以得到這樣的輸出
ProcessBuilder pb = new ProcessBuilder(args);
Process p = pb.start();
//below code gets the output from the process
InputStream in = p.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
InputStreamReader inread = new InputStreamReader(buf);
BufferedReader bufferedreader = new BufferedReader(inread);
String line;
while ((line = bufferedreader.readLine()) != null) {
*do something / collect output*
}
我已經為此苦苦掙扎了一段時間,但我想你能做的最簡單的事情是自己傳輸流,使用某種 StreamTransfer 類,你可以說哪個InputStream
在單獨的線程中寫入哪個OutputStream
以避免死鎖。 在這個例子中,我執行ls
然后cat
和手動接線stdout
的ls
入stdin
的cat
,然后cat
的stdout
到System.out
打印的最終結果:
public class TestRedirectingStreams {
public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService threads = Executors.newFixedThreadPool(10);
Process echo = Runtime.getRuntime().exec("ls"),
cat = Runtime.getRuntime().exec("cat");
threads.submit(StreamTransfer.transfer(echo.getInputStream(), cat.getOutputStream()));
threads.submit(StreamTransfer.transfer(cat.getInputStream(), System.out));
threads.shutdown();
}
}
class StreamTransfer implements Callable<Void> {
public static final int BUFFER_SIZE = 1024;
private InputStream in;
private OutputStream out;
public static StreamTransfer transfer(InputStream in, OutputStream out) {
return new StreamTransfer(in, out);
}
private StreamTransfer(InputStream in, OutputStream out) {
this.in = in;
this.out = out;
}
@Override
public Void call() throws Exception { // write to streams when thread executes
byte[] buffer = new byte[BUFFER_SIZE];
int read = 0;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
in.close();
out.close();
return null;
}
}
如果您想改用 ProcessBuilder,示例保持不變,因為ProcessBuilder.start()
返回流程,您仍然可以檢索所需的流並進行相應的傳輸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.