Как мне перехватить вывод java.io.PrintStream в JEditorPane?

Я пытаюсь создать программу Java, в которой пользователь может выбрать любой файл .class или .jar со своего компьютера. Затем моя программа отобразит JInternalFrame с JEditorPane в качестве консоли, перехватив любой консольный вывод из пользовательской программы. Обратите внимание, что я не хочу захватывать только вызовы System.err или System.out, а ВСЕ вызовы PrintStream, которые идут на консоль.

(отдельный вопрос от запущенной программы в стиле IDE)


person Ky Leggiero    schedule 29.10.2010    source источник


Ответы (2)


Вы можете поймать все, что печатается через System.out, используя System.setOut следующим образом:

import java.io.*;

class SystemOutLogging {

    public static void main(String[] args) throws IOException,
                                                  ClassNotFoundException {
        final PrintStream original = System.out;

        System.setOut(new PrintStream("programlog.txt") {
            public void println(String str) {
                process(str + "\n");
            }

            public void print(String str) {
                process(str);
            }

            private void process(String str) {
                // Fill some JEditorPane
                original.println("Program printed: \"" + str + "\"");
            }
        });

        System.out.print("Hello ");
        System.out.println(" World");
    }
}

Отпечатки:

Program printed: "Hello "
Program printed: " World
"

(Существует System.setErr и System.setIn работает аналогично.)

Если вы хотите поймать то, что «подпрограмма» печатает через System.out.println, у вас проблемы, потому что System.out является статическим, поэтому, если вы запустите несколько «подпрограмм», вы получите беспорядок (поскольку вы не можете передать отдельный System класса для каждой подпрограммы).

В такой ситуации я искренне считаю, что было бы лучше запустить отдельный процесс через ProcessBuilder. Стандартные входные/выходные потоки результирующего процесса можно было легко логировать.

(p.s. Когда я думаю об этом, вы, вероятно, могли бы проверить текущую группу потоков в реализации println и исходя из этого решить, какая подпрограмма фактически вызвала метод println)

person aioobe    schedule 29.10.2010
comment
Такие IDE, как NetBeans, похоже, без проблем перехватывают вызовы System.out нескольких программ. Кроме того, это не касается части размещения всех вызовов в JEditorPane. - person Ky Leggiero; 29.10.2010
comment
NetBeans и Eclipse — чрезвычайно сложные программные продукты. Не ожидайте, что сможете воспроизвести их системы. Пример, который я предоставил, дает вам метод процесса. Вы делаете все, что вам нужно, со строками в этом методе. С этого момента добавление его в JEditorPane не должно быть слишком сложным. - person aioobe; 29.10.2010
comment
хотя это правда, что один программист должен воздержаться, прежде чем пытаться что-то размером с Eclipse или NetBeans, они все еще остаются просто программами. Воспроизведение части их функциональности (в данном случае захват выходных данных процесса) не обязательно сложно или выходит за рамки разумных ожиданий. - person Burleigh Bear; 30.10.2010
comment
@Burleigh Bear, согласен. Однако в этом случае он не хочет создавать новый процесс. Я, например, не вижу, как решить это элегантно... - person aioobe; 30.10.2010
comment
ах, я не читал его другой вопрос. Дурак я. Кстати, мне нравится твой p.s. в ответ. +1. - person Burleigh Bear; 30.10.2010

Если вы запускаете файл .jar пользователя с помощью Runtime.exec(), вы получите объект Process. Этот объект позволит вам получить доступ к запущенным процессам System.out, System.in и System.err.

См.: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Process.html

Вы можете читать потоки err и out и добавлять их в свой JEditorPane, используя обычные методы типа setText.

person Burleigh Bear    schedule 29.10.2010
comment
Если бы вы прочитали соответствующий вопрос, вы бы знали, что он не рассматривает это как вариант. - person aioobe; 30.10.2010