Wie arbeitet man mit Datenströmen?

Datenströme sind kontinuierliche Abfolgen von Daten eines Typs, die in Java in die beiden Gruppen der Byte-orientierten und der Zeichen-orientierten Ströme untergliedert werden.

Die Byte-orientierten Ströme sind von den abstrakten Klassen InputStream und OutputStream, die Zeichen-orientierten Ströme von den ebenfalls abstrakten Klassen Reader und Writer abgeleitet.

Der allgemeine Umgang mit Datenströmen sei hier beispielhaft an einem DataInputStream erläutert. Er liest primitive Daten von einem zugrunde liegenden InputStream, hier mittels eines FileInputStream, der Methoden zum Auslesen von Datein bereitstellt. Die geschachtelte Verwendung zweier Ströme, ist in Java verbreitet. Ein erster Stream liest die Rohdaten aus der jeweiligen ggf. Maschinen- und Betriebssystem-abhängigen Quelle und reicht sie weiter zu einer spezifischeren Auswertung, die durch eine Reihe spezialisierter Streams erfolgt (s.u.). Diese besitzen Methoden zur adäquaten Handhabung der jeweiligen Daten.

DataInputStream in = null;
    int i;
    try {
        in = new DataInputStream(new FileInputStream("test.txt"));
        while ((i = in.read()) != -1)
            System.out.print(i);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (in != null) in.close();
        } catch (IOException ioe) {}
    }

Bei der Verarbeitung von Streams können je nach Art des Stroms mannigfaltige Fehler auftreten: Die zu lesende Datei kann nicht gefunden werden, beim Auslesen können Probleme auftreten, der Speicherplatz kann zu Ende gehen, etc. Diese möglichen Fehler müssen gesichert abgefangen werden. Dies geschieht in einem try-catch-Block. In seinem finally-Abschnitt ist dieser zudem für ein geordnetes Schließen des Stroms verantwortlich, da er auf jeden Fall ausgeführt wird, unabhängig davon, ob die Anweisungen im try-Block erfolgreich ausgeführt werden konnten oder nicht.
Da beim Schließen des Stroms durch die Methode close() wiederum eine IOException geworfen werden kann, muss hier nochmals ein try-catch-Block eingesetzt werden.

try-with-resources Statement

7.0Wie deutlich erkennbar, so führt diese Konstruktion zu einem aufgeblähten, schlecht lesbaren Code.
Ab der Java-Version 7 ist es möglich, durch ein try-with-resources Statement dies erheblich zu vereinfachen und das Schließen des Stroms automatisch auszuführen.
Unter einer resource wird hierbei ein Objekt verstanden, das nach Beendigung seiner Aufgaben geschlossen werden muss. Hierzu gehören alle Objekte, die das Interface java.lang.AutoClosable implementieren.
Das obige Code-Beispiel kann hierzu auf die u.a. Weise umgeformt werden. Das Einbetten des Codes in einen try-catch-Block ergibt sich hierbei aus der Notwendigkeit, dass die im Hintergrund ausgeführte Methode close() wie oben bereits erläutert ihrerseites eine IOException auslösen kann.
In den auf javabeginners.de gezeigten Code-Beispielen wird nicht durchgängig, aber weitgehend auf das automatische Schließen von Streams verzichtet, um die Abwärtskompatibilität zu gewährleisten.

int i;
try (DataInputStream in = new DataInputStream(new FileInputStream("test.txt"))) {
    while ((i = in.read()) != -1)
        System.out.print(i);
} catch (IOException e) {
    e.printStackTrace();
}

Die wesentlichen Stream-Klassen im Überblick

Die folgenden Auflistungen und schematischen Darstellungen von Zeichen- und Byte-orientierten Strömen und deren Klassenhierarchien sind nicht vollständig, sondern zeigen nur die gebräuchlisten Ströme.

Von Reader abgeleitete Klassen:

Ihr Browser unterstützt das HTML5-Canvaselement nicht.

Anwendungsbeispiele

BufferedReader
Programm starten
HTML-Seite darstellen
Von Tastatur lesen
Von Tastatur in Datei schreiben
InputStreamReader
Programm starten
HTML-Seite darstellen
Von Tastatur lesen
FileReader
Eine Datei zeilenweise auslesen
Eine Datei auslesen
Json lesen

Von Writer abgeleitete Klassen:

Ihr Browser unterstützt das HTML5-Canvaselement nicht.

Anwendungsbeispiele

BufferedWriter
In Textdatei schreiben
PrintWriter
Browser starten
ArrayList in Datei schreiben
FileWriter
Von Tastatur in Datei schreiben
In Textdatei schreiben
OutputStreamWriter
XML-Datei lesen

Von InputStream abgeleitete Klassen:

Ihr Browser unterstützt das HTML5-Canvaselement nicht.

Anwendungsbeispiele

InputStream
Browser starten
Programm starten
HTML-Seite darstellen
BufferedInputStream
Primitive_Datentypen_speichern
DataInputStream
Primitive_Datentypen_speichern
ObjectInputStream
Daten serialisieren
FileInputStream
Byte-Array speichern und lesen
Verzeichnisinhalt packen
Eine Datei kopieren
Primitive_Datentypen_speichern

Von OutputStream abgeleitete Klassen:

Ihr Browser unterstützt das HTML5-Canvaselement nicht.

Anwendungsbeispiele

BufferedOutputStream
Primitive_Datentypen_speichern
ObjectOutputStream
Daten serialisieren
FileOutputStream
Byte-Array speichern und lesen
Eine Datei kopieren
PDF schreiben
Primitive_Datentypen_speichern
XML-Datei schreiben
PrintStream
Socketverbindung
ZipOutputStream
Verzeichnisinhalt packen