Запуск процесса с унаследованным stdin/stdout/stderr в Java 6
Вопрос
Если я запускаю процесс через Java ProcessBuilder класса, у меня есть полный доступ к стандартным потокам ввода, вывода и стандартным потокам ошибок этого процесса, поскольку Java InputStreams
и OutputStreams
.Однако я не могу найти способ беспрепятственно соединить эти потоки с System.in
, System.out
, и System.err
.
Можно использовать redirectErrorStream()
чтобы получить сингл InputStream
который содержит стандартный вывод подпроцесса и стандартную ошибку, и просто прохожу его и отправляю через мой стандартный вывод - но я не могу найти способ сделать это и позволить пользователю вводить данные в процесс, как он или она могли бы, если бы я использовал букву С system()
вызов.
Кажется, это возможно в Java SE 7, когда она выйдет — мне просто интересно, есть ли обходной путь сейчас.Бонусные баллы, если результат isatty()
в дочернем процессе осуществляется перенаправление.
Решение
Вам нужно будет скопировать Процесс 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();
Другие советы
Вариант ответа Джона, который компилируется и не требует использования 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();
}
Для 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();
}