Подтвердить что ты не робот

Как я могу прочитать вывод Java Console в буфере String

У меня есть Java-программа, которая выводит некоторый текст в консоль. Он использует print, println и некоторые другие методы для этого.

В конце программы я хочу прочитать весь текст в консоли и скопировать его в буфер String. Как я могу сделать это на Java? Мне нужно отдельно читать stdout и stderr.

4b9b3361

Ответ 1

Хорошо, это была забавная проблема. Кажется, Dosen't является изящным способом его решения для всех методов PrintStream. (К сожалению, нет FilterPrintStream.)

Я действительно написал уродливое обходное решение, основанное на размышлениях (не для использования в производственном коде, я полагаю:)

class LoggedPrintStream extends PrintStream {

    final StringBuilder buf;
    final PrintStream underlying;

    LoggedPrintStream(StringBuilder sb, OutputStream os, PrintStream ul) {
        super(os);
        this.buf = sb;
        this.underlying = ul;
    }

    public static LoggedPrintStream create(PrintStream toLog) {
        try {
            final StringBuilder sb = new StringBuilder();
            Field f = FilterOutputStream.class.getDeclaredField("out");
            f.setAccessible(true);
            OutputStream psout = (OutputStream) f.get(toLog);
            return new LoggedPrintStream(sb, new FilterOutputStream(psout) {
                public void write(int b) throws IOException {
                    super.write(b);
                    sb.append((char) b);
                }
            }, toLog);
        } catch (NoSuchFieldException shouldNotHappen) {
        } catch (IllegalArgumentException shouldNotHappen) {
        } catch (IllegalAccessException shouldNotHappen) {
        }
        return null;
    }
}

..., который можно использовать следующим образом:

public class Test {
    public static void main(String[] args) {

        // Create logged PrintStreams
        LoggedPrintStream lpsOut = LoggedPrintStream.create(System.out);
        LoggedPrintStream lpsErr = LoggedPrintStream.create(System.err);

        // Set them to stdout / stderr
        System.setOut(lpsOut);
        System.setErr(lpsErr);

        // Print some stuff
        System.out.print("hello ");
        System.out.println(5);
        System.out.flush();

        System.err.println("Some error");
        System.err.flush();

        // Restore System.out / System.err
        System.setOut(lpsOut.underlying);
        System.setErr(lpsErr.underlying);

        // Print the logged output
        System.out.println("----- Log for System.out: -----\n" + lpsOut.buf);
        System.out.println("----- Log for System.err: -----\n" + lpsErr.buf);
    }
}

Результат:

hello 5
Some error
----- Log for System.out: -----
hello 5

----- Log for System.err: -----
Some error

(Обратите внимание, что поле out в FilterOutputStream защищено и задокументировано, поэтому оно является частью API: -)

Ответ 2

Вы не можете сделать это, как только программа будет завершена. Вам нужно сделать это, прежде чем программа начнет запись вывода.

Подробнее о замене stdout и stderr см. в этой статье. Основные вызовы: System.setOut() и System.setErr().

Ответ 3

Вы можете использовать PipedInputStream и PipedOutputStream.

//create pairs of Piped input and output streasm for std out and std err
final PipedInputStream outPipedInputStream = new PipedInputStream();
final PrintStream outPrintStream = new PrintStream(new PipedOutputStream(
    outPipedInputStream));
final BufferedReader outReader = new BufferedReader(
    new InputStreamReader(outPipedInputStream));
final PipedInputStream errPipedInputStream = new PipedInputStream();
final PrintStream errPrintStream = new PrintStream(new PipedOutputStream(
    errPipedInputStream));
final BufferedReader errReader = new BufferedReader(
    new InputStreamReader(errPipedInputStream));
final PrintStream originalOutStream = System.out;
final PrintStream originalErrStream = System.err;
final Thread writingThread = new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            System.setOut(outPrintStream);
            System.setErr(errPrintStream);
            // You could also set the System.in here using a
            // PipedInputStream
            DoSomething();
            // Even better would be to refactor DoSomething to accept
            // PrintStream objects as parameters to replace all uses of
            // System.out and System.err. DoSomething could also have 
            // an overload with DoSomething() calling: 
            DoSomething(outPrintStream, errPrintStream);
        } finally {
            // may also want to add a catch for exceptions but it is
            // essential to restore the original System output and error
            // streams since it can be very confusing to not be able to
            // find System.out output on your console
            System.setOut(originalOutStream);
            System.setErr(originalErrStream);
            //You must close the streams which will auto flush them
            outPrintStream.close();
            errPrintStream.close();
        }
    } // end run()
}); // end writing thread
//Start the code that will write into streams
writingThread.start();
String line;
final List<String> completeOutputStreamContent = new ArrayList<String>();
while ((line = outReader.readLine()) != null) {
    completeOutputStreamContent.add(line);
} // end reading output stream
final List<String> completeErrorStreamContent = new ArrayList<String>();
while ((line = errReader.readLine()) != null) {
    completeErrorStreamContent.add(line);
} // end reading output stream

Ответ 4

Не делайте этого после этого, создайте два объекта StringBuilder до того, как будет вызван первый System.out.print(), и просто добавьте каждую строку, которую вы хотите сохранить, к соответствующему StringBuilder.

Ответ 5

Эти две строки кода помещают ваш вывод в текстовый файл, или вы можете изменить назначение, как вам нужно.

//Создаем файл:       System.setOut(новый PrintStream (новый FileOutputStream ( "D:/MyOutputFile.txt" )));       // Перенаправить вывод в файл:       System.out.println( "Привет, пользовательский поток вывода!" );

надеюсь, что он поможет вам...:)

Ответ 6

Вот класс утилиты с именем ConsoleOutputCapturer. Он позволяет выводить выход на существующую консоль, однако позади сцены сохраняется захват выходного текста. Вы можете управлять захватом с помощью методов старт/стоп. Другими словами, вызовите начало запуска захвата вывода консоли, и как только вы закончите захват, вы можете вызвать метод stop, который возвращает значение String, содержащее вывод консоли для временного окна между вызовами start-stop. Однако этот класс не является потокобезопасным.

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;

public class ConsoleOutputCapturer {
    private ByteArrayOutputStream baos;
    private PrintStream previous;
    private boolean capturing;

    public void start() {
        if (capturing) {
            return;
        }

        capturing = true;
        previous = System.out;      
        baos = new ByteArrayOutputStream();

        OutputStream outputStreamCombiner = 
                new OutputStreamCombiner(Arrays.asList(previous, baos)); 
        PrintStream custom = new PrintStream(outputStreamCombiner);

        System.setOut(custom);
    }

    public String stop() {
        if (!capturing) {
            return "";
        }

        System.setOut(previous);

        String capturedValue = baos.toString();             

        baos = null;
        previous = null;
        capturing = false;

        return capturedValue;
    }

    private static class OutputStreamCombiner extends OutputStream {
        private List<OutputStream> outputStreams;

        public OutputStreamCombiner(List<OutputStream> outputStreams) {
            this.outputStreams = outputStreams;
        }

        public void write(int b) throws IOException {
            for (OutputStream os : outputStreams) {
                os.write(b);
            }
        }

        public void flush() throws IOException {
            for (OutputStream os : outputStreams) {
                os.flush();
            }
        }

        public void close() throws IOException {
            for (OutputStream os : outputStreams) {
                os.close();
            }
        }
    }
}