Запуск процесса с унаследованным stdin / stdout / stderr в Java 6 - PullRequest
28 голосов
/ 13 сентября 2008

Если я запускаю процесс через класс Java ProcessBuilder , я получаю полный доступ к стандартным входным, стандартным и стандартным ошибочным потокам этого процесса, таким как Java InputStreams и OutputStreams. Тем не менее, я не могу найти способ бесшовного подключения этих потоков к System.in, System.out и System.err.

Можно использовать redirectErrorStream(), чтобы получить один InputStream, который содержит стандартный вывод и стандартную ошибку подпроцесса, и просто выполнить цикл и отправить его через мой стандартный вывод, но я не могу найти способ сделать это и позволить пользователю ввести в процесс, как он или она могли бы, если бы я использовал вызов C system().

Это представляется возможным в Java SE 7, когда она выйдет - мне просто интересно, есть ли обходной путь сейчас. Бонусные баллы, если результат isatty() в дочернем процессе проходит через перенаправление.

Ответы [ 3 ]

16 голосов
/ 13 сентября 2008

Вам потребуется скопировать Process out, err и входные потоки в версии системы. Самый простой способ сделать это - использовать класс IOUtils из пакета 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();
13 голосов
/ 15 октября 2009

Вариант ответа Джона, который компилируется и не требует использования 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();
}
3 голосов
/ 10 июня 2011

Для System.in используйте следующее pipein() вместо pipe()

pipein(System.in, p.getOutputStream());

Реализация:

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

}
...