我怎样才能将Java控制台输出读入String缓冲区

我有一个Java程序,可以将一些文本输出到控制台。 它使用printprintln和其他一些方法来完成此操作。

在程序结束时,我想读取控制台中的所有文本并将其复制到String缓冲区中。 我怎么能用Java做到这一点? 我需要分别阅读stdoutstderr

好的,这是一个有趣的问题。 对于所有PrintStream方法,它似乎不是一种优雅的解决方法。 (不幸的是没有FilterPrintStream 。)

我确实编写了一个丑陋的基于reflection的解决方法(不要在生产代码中使用我想:)

 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 

(请注意, FilterOutputStream中的out字段受到保护并记录,因此它是API的一部分:-)

程序运行完毕后,您无法执行此操作。 您需要在程序开始写输出之前执行此操作。

有关如何替换stdout和stderr的详细信息,请参阅此文章 。 核心调用是System.setOut()System.setErr()

您可以使用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 completeOutputStreamContent = new ArrayList(); while ((line = outReader.readLine()) != null) { completeOutputStreamContent.add(line); } // end reading output stream final List completeErrorStreamContent = new ArrayList(); while ((line = errReader.readLine()) != null) { completeErrorStreamContent.add(line); } // end reading output stream 

这是一个名为ConsoleOutputCapturer的实用程序类。 它允许输出转到现有控制台,但在场景后面继续捕获输出文本。 您可以使用start / stop方法控制要捕获的内容。 换句话说,调用start开始捕获控制台输出,一旦完成捕获,就可以调用stop方法,该方法返回一个String值,该值保存控制台输出,用于启动 – 停止调用之间的时间窗口。 但是这个类不是线程安全的。


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 outputStreams; public OutputStreamCombiner(List 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(); } } } }

之后不要这样做,在调用第一个System.out.print()之前创建两个StringBuilder对象,然后将要保存的每个字符串追加到相应的StringBuilder

这两行代码会将您的输出放在一个文本文件中,或者您可以根据需要更改目标。

//创建文件:System.setOut(new PrintStream(new FileOutputStream(“D:/MyOutputFile.txt”))); //将输出重定向到文件:System.out.println(“Hello to custom output stream!”);

希望对你有所帮助.. 🙂