在Java6中使用继承的stdin/stdout/stderr启动进程

在Java6中使用继承的stdin/stdout/stderr启动进程,java,io,process,pipe,Java,Io,Process,Pipe,如果我通过Java的类启动一个进程,我可以完全访问该进程的标准输入、标准输出和标准错误流,如JavaInputStreams和OutputStreams。但是,我无法找到一种方法将这些流无缝连接到System.in、System.out和System.err 可以使用redirectErrorStream()获取包含子流程的标准输出和标准错误的单个InputStream,然后循环并通过我的标准输出发送,但我找不到这样做的方法,让用户输入流程,如果我使用Csystem()调用,他或她可能会这样做

如果我通过Java的类启动一个进程,我可以完全访问该进程的标准输入、标准输出和标准错误流,如Java
InputStreams
OutputStreams
。但是,我无法找到一种方法将这些流无缝连接到
System.in
System.out
System.err

可以使用
redirectErrorStream()
获取包含子流程的标准输出和标准错误的单个
InputStream
,然后循环并通过我的标准输出发送,但我找不到这样做的方法,让用户输入流程,如果我使用C
system()
调用,他或她可能会这样做

这在JavaSE7中出现时似乎是可能的——我只是想知道现在是否有解决办法。如果子进程中的结果执行重定向,则可获得额外积分。

您需要将输出、错误和输入流复制到系统版本。最简单的方法是使用Commons IO包中的类。这看起来正是你需要的。复制方法调用需要在单独的线程中进行

以下是基本代码:

// Assume you already have a processBuilder all configured and ready to go
final Process process = processBuilder.start();
new Thread(new Runnable() {public void run() {
  IOUtils.copy(process.getOutputStream(), System.out);
} } ).start();
new Thread(new Runnable() {public void run() {
  IOUtils.copy(process.getErrorStream(), System.err);
} } ).start();
new Thread(new Runnable() {public void run() {
  IOUtils.copy(System.in, process.getInputStream());
} } ).start();

John答案的一个变体,编译后不需要您使用Commons IO:

private static void pipeOutput(Process process) {
    pipe(process.getErrorStream(), System.err);
    pipe(process.getInputStream(), System.out);
}

private static void pipe(final InputStream src, final PrintStream dest) {
    new Thread(new Runnable() {
        public void run() {
            try {
                byte[] buffer = new byte[1024];
                for (int n = 0; n != -1; n = src.read(buffer)) {
                    dest.write(buffer, 0, n);
                }
            } catch (IOException e) { // just exit
            }
        }
    }).start();
}

对于
系统。在
中,使用以下
pipein()
而不是
pipe()

实施:

private static void pipein(final InputStream src, final OutputStream dest) {

    new Thread(new Runnable() {
        public void run() {
            try {
               int ret = -1;
               while ((ret = System.in.read()) != -1) {
                  dest.write(ret);
                  dest.flush();
               }
            } catch (IOException e) { // just exit
            }
        }
    }).start();

}

太好了-我只是想知道如何做到这一点。是的,Stackoverflow:)不太好。copy将InputStream作为它的第一个参数,因此这不适用于getOutputStream。所以它是IOUtils.copy(process.getInputStream(),System.out);这有点让人困惑,因为getOutputStream实际上是通过管道传输到流程的输入端的。getInputStream()是应该通过管道传输到stdout的进程(是的,听起来倒过来)。因此,虽然这个结构看起来不错,但对IOUtils的调用看起来是错误的,现在让我有点困惑…错误。这只是在父级和子级的输入/输出流之间传输数据,不允许它继承它们。例如,即使Java命令是在终端上启动的(C isatty()==true或System.console()!=null),子级也不会认为自己正在终端中运行,因为其输入/输出流是管道。这一点很重要,因为某些(大多数)程序在终端中运行时表现不同。Java 7的ProcessBuilder.Redirect.INHERIT在这方面工作正常;好像不管用?
private static void pipein(final InputStream src, final OutputStream dest) {

    new Thread(new Runnable() {
        public void run() {
            try {
               int ret = -1;
               while ((ret = System.in.read()) != -1) {
                  dest.write(ret);
                  dest.flush();
               }
            } catch (IOException e) { // just exit
            }
        }
    }).start();

}