Jacob
Jacob

Reputation: 835

How could I read Java Console Output into a String buffer

I have a Java program that outputs some text into console. It uses print, println, and some other methods to do this.

At the end of the program , I want to read all the text in console and copy it into a String buffer. How could I do this in Java ? I need to read stdout and stderr separately.

Upvotes: 17

Views: 27458

Answers (7)

Daniils Loptevs
Daniils Loptevs

Reputation: 11

Simple decision by implement pattern Decorator and set System.out & System.err

Implementation

import java.io.PrintStream;

/** Simple implementation of pattern Decorator. */
public class SystemOutputProxy extends PrintStream {
    private final PrintStream printStream;
    private final StringBuilder sb;
    
    public SystemOutputProxy(PrintStream printStream, StringBuilder sb) {
        super(printStream);
        this.printStream = printStream;
        this.sb = sb;
    }
    
    @Override public void print(Object obj) {
        sb.append(obj);
        printStream.print(obj);
    }
    
    @Override public void print(String x) {
        sb.append(x);
        printStream.println(x);
    }
    
    
    /* override all others overloading of method: print(...) */
    
    
    @Override public void println(Object x) {
        sb.append(x).append(System.lineSeparator());
        printStream.println(x);
    }
    
    @Override public void println(String x) {
        sb.append(x).append(System.lineSeparator());
        printStream.println(x);
    }
    
    
    /* override all others overloading of method: println(...) */
    
    
    @Override public PrintStream printf(String format, Object... args) {
        sb.append(String.format(format, args));
        return printStream.printf(format, args);
    }
    
    
    /* override all others overloading of method: printf(...) */
    
    
    public PrintStream getPrintStream() {
        return printStream;
    }
     
}

Using showcase

    public static void main(String[] args) {
        StringBuilder out = new StringBuilder();
        StringBuilder err = new StringBuilder();
        SystemOutputProxy proxyOut = new SystemOutputProxy(System.out, out);
        SystemOutputProxy proxyErr = new SystemOutputProxy(System.err, err);
        System.setOut(proxyOut);
        System.setErr(proxyErr);
        
        // do your code here...
        System.out.print("aaa");
        System.out.print("bbb");
        System.out.print("ccc");
        
        System.err.print("111");
        System.err.print("222");
        System.err.print("333");
        // finish your code...
        
        // set back original Output is not necessary
        System.setOut(proxyOut.getPrintStream());
        System.setErr(proxyErr.getPrintStream());
        
        boolean isOurContentEquals = out.toString().equals("aaabbbccc");
        boolean isErrContentEquals = err.toString().equals("111222333");
        
        System.out.println("isOurContentEquals = " + isOurContentEquals); // show true
        System.out.println("isErrContentEquals = " + isErrContentEquals); // show true
    }

Console show

aaa
bbb
ccc
isOurContentEquals = true
isErrContentEquals = true
111
222
333

Upvotes: 0

unwind
unwind

Reputation: 400159

You can't do that once the program is finished running. You need to do it before the program starts to write output.

See this article(archive.org) for details on how to replace stdout and stderr. The core calls are System.setOut() and System.setErr().

Upvotes: 6

Manasjyoti Sharma
Manasjyoti Sharma

Reputation: 321

Here is a utility Class named ConsoleOutputCapturer. It allows the output to go to the existing console however behind the scene keeps capturing the output text. You can control what to capture with the start/stop methods. In other words call start to start capturing the console output and once you are done capturing you can call the stop method which returns a String value holding the console output for the time window between start-stop calls. This class is not thread-safe though.

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

Upvotes: 1

Muhammad Suleman
Muhammad Suleman

Reputation: 2932

These two line of code will put your output in a text file or u can change the destination as u require.

// Create a file: System.setOut(new PrintStream( new FileOutputStream("D:/MyOutputFile.txt"))); // Redirect the output to the file: System.out.println("Hello to custom output stream!");

hope its help u .. :)

Upvotes: 0

PeterVermont
PeterVermont

Reputation: 2002

You can use PipedInputStream and 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

Upvotes: 1

aioobe
aioobe

Reputation: 421340

Ok, this was a fun problem. Dosen't seem to be an elegant way of solving it for all PrintStream methods at once. (Unfortunately there is no FilterPrintStream.)

I did write up an ugly reflection-based workaround though (not to be used in production code I suppose :)

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;
    }
}

...that can be used like this:

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

Resulting output:

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

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

(Note though, that the out field in FilterOutputStream is protected and documented, so it is part of the API :-)

Upvotes: 17

Vladimir Ivanov
Vladimir Ivanov

Reputation: 43108

Don't do it afterwards, create two StringBuilder objects before the first System.out.print() gets called and just append every string you want to save to the appropriate StringBuilder.

Upvotes: 0

Related Questions