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!");
  }
}
Previous Article
Next Article

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.