是否可以将输出流重定向回进程,或者根本不重定向它?
背景故事:我正在尝试使用 processbuilder 启动一个可执行文件。(确切地说是源专用服务器/srcds.exe)
由于使用 processbuilder 启动它,这个可执行文件的控制台窗口仍然是空的。启动几秒钟后,可执行文件崩溃并显示错误“CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents”,因为它的控制台是空的。
是否可以将输出流重定向回进程,或者根本不重定向它?
背景故事:我正在尝试使用 processbuilder 启动一个可执行文件。(确切地说是源专用服务器/srcds.exe)
由于使用 processbuilder 启动它,这个可执行文件的控制台窗口仍然是空的。启动几秒钟后,可执行文件崩溃并显示错误“CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents”,因为它的控制台是空的。
我认为您正在谈论使启动的进程'stdout 转到当前进程'stdout。如果您使用的是 JDK7,那很简单:
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
更新:(评论太多)我认为你很困惑。当您从终端启动进程时,该进程将成为该终端进程的子进程,并将标准输出发送到该终端。当您从 Java 启动进程时,该进程是 Java 进程的子进程,其标准输出将发送到 Java。
在第一种情况下,有一个显示标准输出的终端,因为您自己从终端启动了它,这就是终端对标准输出所做的事情。然而,当从 Java 启动时,不会有终端窗口,除非您启动的进程中的某些东西打开了一个终端,并且您启动的进程的标准输出被交还给程序员,您可以随意处理。从终端启动时看到的等效行为是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
thencat
并手动将stdout
ofls
连接到stdin
of cat
,然后cat
's stdout
toSystem.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()
返回进程,您仍然可以检索所需的流并相应地传输。