Как сделать программу java для печати как out.println(), так и err.println() операторов?

Я написал код java ниже, который выполняет другую java-программу под названием "Newsworthy_RB".

Newsworthy_RB.java содержит как операторы System.out.printlln(), так и System.err.println().

Я хочу, чтобы оба вывода печатались в консоли командной строки.

Что нужно сделать для того, чтобы получить то же самое.

В приведенной ниже программе просто печатаются инструкции out.println(), а не инструкции err.println().

Пожалуйста, дайте мне знать, будет ли код ниже функционировать, как я ожидаю?

command = "java -cp .:../sqljdbc.jar SetHash Newsworthy_RB";
Process child1 = Runtime.getRuntime().exec(command);
InputStream in1 = child1.getErrorStream();
InputStream in2 = child2.getInputStream();
while ((c = in1.read()) != -1 || (c = in2.read()) != -1) {
        System.out.print((char)c);
    }

Ответ 1

Прежде всего, предпочтительный способ запуска внешних программ - ProcessBuilder. Это даже упоминается в документах для Runtime:

ProcessBuilder.start() теперь является предпочтительным способом запуска процесса с измененной средой.

В ProcessBuilder у вас есть очень удобный метод redirectErrorStream:

Устанавливает свойство redirectErrorStream этого процесса.

Если это свойство истинно, то любой вывод ошибки, созданный подпроцессами, впоследствии запущенный этим методом start() объекта, будет объединен со стандартным выходом, так что оба могут быть прочитаны с помощью Process. getInputStream(). Это упрощает корреляцию сообщений об ошибках с соответствующим выходом. Начальное значение ложно.

Полный пример того, как выводить как стандартную ошибку, так и стандартную:

import java.io.*;

public class Test {
    public static void main(String... args) throws IOException {

        ProcessBuilder pb =
                new ProcessBuilder("java", "-cp", "yourClassPath", "HelloWorld");

        pb.redirectErrorStream(true);
        Process proc = pb.start();

        Reader reader = new InputStreamReader(proc.getInputStream());
        int ch;
        while ((ch = reader.read()) != -1)
            System.out.print((char) ch);
        reader.close();
    }
}

Ответ на ваше обновление: Нет, код с

while ((c = in1.read()) != -1 || (c = in2.read()) != -1)

не будет работать, поскольку read() является методом блокировки, и у вас есть только один поток. Единственный вариант - использовать один поток для каждого потока ввода или (желательно) объединить два потока ввода в один, используя ProcessBuilder.redirectErrorStream.

Ответ 2

Вам нужно передать вывод обоих потоков в отдельные потоки. Пример кода из здесь:

Process p = Runtime.getRuntime().exec(cmd.array());
copyInThread(p.getInputStream(), System.out);
copyInThread(p.getErrorStream(), System.err);
p.waitFor();
return p.exitValue();

private void copyInThread(final InputStream in, final OutputStream out) {
    new Thread() {
        public void run() {
            try {
                while (true) {
                    int x = in.read();
                    if (x < 0) {
                        return;
                    }
                    if (out != null) {
                        out.write(x);
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    } .start();
}

Ответ 3

В объекте Process есть два метода: getErrorStream и getInputStream. В настоящее время ваша программа только слушает. Вы хотите, чтобы он слушал оба.