2010-12-02 6 views
12

Ich habe ein Java-Programm, das etwas Text in die Konsole ausgibt. Es verwendet print, println und einige andere Methoden, um dies zu tun.Wie konnte ich Java Console Output in einen String-Puffer lesen

Am Ende des Programms möchte ich den gesamten Text in der Konsole lesen und in einen String-Puffer kopieren. Wie könnte ich das in Java machen? Ich muss stdout und stderr separat lesen.

Antwort

17

Ok, das war ein lustiges Problem. Es scheint nicht eine elegante Art zu sein, es für alle Methoden auf einmal zu lösen. (Leider gibt es keine FilterPrintStream.)

Ich habe allerdings eine hässliche Reflexion basierte Abhilfe schreiben (nicht im Produktionscode verwendet werden Ich nehme an :)

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

... das kann wie verwendet werden dies:

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

resultierende Ausgang:

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

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

(Hinweis tho ugh, dass das out Feld in FilterOutputStream geschützt und dokumentiert ist, so ist es Teil der API :-)

+1

Wow! Danke vielmals. Für mich geht das. – Jacob

+0

Ich kann die 3 Zeilen nicht bekommen. Ausgehend von 'Field f' bis' f.get (toLog) '. Kann mir das jemand erklären? –

5

Sie können das nicht tun, sobald das Programm fertig ist. Sie müssen dies tun, bevor das Programm beginnt, die Ausgabe zu schreiben.

Weitere Informationen zum Ersetzen von stdout und stderr finden Sie unter this article. Die Kernaufrufe sind System.setOut() und System.setErr().

0

Tun Sie es nicht danach, erstellen Sie zwei StringBuilder Objekte vor dem ersten System.out.print() aufgerufen wird, und fügen Sie einfach jede Zeichenfolge, die Sie auf den entsprechenden StringBuilder speichern möchten.

1

Sie können PipedInputStream und PipedOutputStream verwenden.

0

Diese zwei Codezeilen bringen Ihre Ausgabe in eine Textdatei oder Sie können das Ziel ändern, wie Sie es benötigen.

// Erstellen Sie eine Datei: System.setOut (neuer PrintStream (neuer FileOutputStream ("D: /MyOutputFile.txt")))); // Leiten Sie die Ausgabe in die Datei um: System.out.println ("Hallo zum benutzerdefinierten Ausgabestream!");

hoffen, seine Hilfe u .. :)

0

hier eine ConsoleOutputCapturer namens Utility-Klasse ist. Es erlaubt der Ausgabe, zu der vorhandenen Konsole zu gehen, aber hinter der Szene erfasst weiterhin den ausgegebenen Text. Sie können steuern, was mit den Start/Stopp-Methoden erfasst werden soll. Mit anderen Worten, rufen Sie start an, um die Konsolenausgabe zu erfassen, und sobald Sie fertig sind, können Sie die Methode stop aufrufen, die einen String-Wert zurückgibt, der die Konsolenausgabe für das Zeitfenster zwischen Start-Stopp-Aufrufen enthält. Diese Klasse ist jedoch nicht Thread-sicher.

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