09.06 Die Standardeingabe/ausgabe
Sie haben bereits mehrfach mit der Standardausgabe System.out.println
gearbeitet. Dieser Stream muss jedoch nicht zwingend auf der Konsole ausgegeben werden. In diesem Kapitel lernen Sie, wie Sie die Standardausgabe umleiten und Text von der Konsole einlesen.
Text von der Konsole einlesen
Bis jetzt konnten Sie den Ablauf Ihrer Programme nur umständlich durch Parameterübergabe an die Main-Klasse direkt beim Programmstart vom User beeinflussen lassen. Benutzereingaben können aber auch während dem Programmablauf vom User über die Konsole empfangen werden. Hierzu verwenden Sie den statischen InputStream in
der Klasse System
:
package de.jbb.io; import java.io.IOException; public class StandardIO { public static void main(String[] args) { try { System.out.println("Bitte druecken Sie eine Taste und bestaetigen mit 'Return'"); char c = (char)System.in.read(); System.out.println("Benutzereingabe: " + c); } catch (IOException e) { e.printStackTrace(); } } }
Drücken Sie nach dem Start des Programms eine beliebige Taste und betätigen anschließend Return. Sie erhalten bspw. eine solche Ausgabe:
Bitte druecken Sie eine Taste und bestaetigen mit 'Return'
a
Benutzereingabe: a
Natürlich ist es nicht gerade praktisch, wenn immer nur ein Zeichen eingelesen werden kann. Um dies zu umgehen, könnte man sich bspw. eine Schleife programmieren, die so lange aus dem InputStream liest, bis ein Zeilenumbruch (\n) eingegeben wurde.
System.out.println("Geben Sie etwas ein und bestaetigen Sie."); char c = 0; StringBuilder str = new StringBuilder(); while ((c = (char)System.in.read()) != '\n') { str.append(c); } System.out.println("Benutzereingabe: " + str.toString());
Noch einfacher geht es jedoch, wenn Sie sich noch einmal das Kapitel 09.04 Datenzugriffe auf das Dateisystem erinnern. Dort konnten Sie mit einem BufferedReader
gleich zeilenweise lesen. Dies funktioniert nicht nur mit FileReadern
, sondern mit jedem beliebigem Reader
. Da in unserem Fall jedoch ein InputStream
vorliegt, müssen Sie zuerst System.in
in einen Reader
konvertieren. Hierzu bietet sich die Klasse java.io.InputStreamReader
an.
System.out.println("Geben Sie etwas ein und bestaetigen Sie."); BufferedReader buffy = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Benutzereingabe: " + buffy.readLine());
Ausgabe:
Geben Sie etwas ein und bestaetigen Sie.
BufferedReader sind sehr Komfortabel
Benutzereingabe: BufferedReader sind sehr Komfortabel
Beachten Sie aber, dass es im Standard-Java keine Möglichkeit gibt, Benutzerdaten von der Konsole einzulesen, die der User nicht mit Enter bestätigt hat.
Konsolenausgaben umleiten
Wenn Sie etwas mit System.out.println
ausgeben, erscheint dies immer auf der Standardausgabe – der Konsole. In manchen Fällen ist es jedoch erforderlich oder nützlich die Ausgabe in eine Datei umzuleiten.
Es gibt allerdings auch spezielle Logging-Tools. Ggf. ist bspw. Log4J für Ihren Einsatzzweck das Richtige!?
Hierzu setzen Sie einfach einen java.io.PrintStream
über System.setOut(PrintStream ps)
. Einem PrintStream
können Sie entweder direkt einen Dateinamen als Ziel übergeben, aber auch bspw. einen eigenen OutputStream
verwenden.
package de.jbb.io; import java.io.FileNotFoundException; import java.io.PrintStream; public class StandardIO { public static void main(String[] args) throws FileNotFoundException { PrintStream out = new PrintStream("C:/test.txt"); System.setOut(out); System.out.println("Testausgabe"); } }
Nach Ausführung des Programms, finden Sie auf C:\ eine Textdatei mit dem Namen test.txt und dem Inhalt Testausgabe.
Die Fehlerausgabe umleiten
Neben der Standardausgabe gibt es auch einen Errorstream. An diesen werden alle Fehlermeldungen im Programm (bspw. exception.printStackTrace()
oder System.err.println("Fehler!")
weitergeleitet. Diesen können Sie ebenfalls auf ganz ähnliche Weise in eine Datei umleiten. Verwenden Sie lediglich den Befehl System.setErr(PrintStream ps)
anstelle von System.setOut(PrintStream ps)
.
PrintStream err = new PrintStream("C:/test.txt"); System.setErr(err); try { Integer.parseInt("ASDF"); } catch (NumberFormatException nfe) { System.err.println("Fehler!"); nfe.printStackTrace(); }
In der Datei finden Sie nun folgenden Text:
Fehler!
java.lang.NumberFormatException: For input string: "ASDF"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at de.jbb.io.StandardIO.main(StandardIO.java:14)
Textausgabe auf der Konsole und in einer Datei
Um die Standardausgabe sowohl in der Konsole anzuzeigen, als auch in eine Datei zu schreiben, wird ein eigener OutputStream
benötigt, der die Ausgabe an beide Ziele weiterleitet.
Auch an dieser Stelle noch einmal der Hinweis auf standardisierte Logging-Tools.
Hierfür programmieren wir uns einen allgemein MultipleOutputStream
, der die Ausgabe an beliebig viele Streams weiterleitet – sofern Sie dem MultipleOutputStream
hinzugefügt wurden.
package de.jbb.io; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class MultipleOutputStream extends OutputStream { // Liste, in der alle Streams gespeichert werden private List<OutputStream> streams = new ArrayList<OutputStream>(); public MultipleOutputStream() {} public MultipleOutputStream(OutputStream os) { this.streams.add(os); } public MultipleOutputStream(Collection<OutputStream> ostreams) { this.streams.addAll(ostreams); } @Override public void write(int i) throws IOException { // Ausgabe an alle Streams weiterleiten for (OutputStream os : this.streams) { os.write(i); } } public void addOutputStream(OutputStream os) { this.streams.add(os); } public void removeOutputStream(OutputStream os) { this.streams.remove(os); } public List<OutputStream> getStreams() { return this.streams; } public void setStreams(List<OutputStream> streams) { this.streams = streams; } }
Nun fügen wir in unserem Beispiel dem MultipleOutputStream
die Standardausgabe (System.out
) und einen FileOutputStream
hinzu. Sobald der MultipleOutputStream
in einen PrintStream
verpackt wurde, können wir ihn als neue Standardausgabe verwenden. Der Text, der nun über System.out.print(ln)()
ausgegeben wird, erscheint dann auf der Konsole und in einer von uns spezifizierten Datei.
package de.jbb.io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; public class StandardIO { public static void main(String[] args) throws FileNotFoundException { FileOutputStream testOut = new FileOutputStream("C:/test.txt"); MultipleOutputStream mos = new MultipleOutputStream(); mos.addOutputStream(System.out); mos.addOutputStream(testOut); System.setOut(new PrintStream(mos)); System.out.println("Ich erscheine auf der Konsole und in einer Datei!"); } }