„Hallo Amigo! Heute werden wir uns mit Eingabe-/Ausgabedatenströmen vertraut machen. Wir haben dieses Thema schon vor ein paar Tagen aufgegriffen, aber heute werden wir alles genauer unter die Lupe nehmen. Eingabe-/Ausgabedatenströme werden in 4 Kategorien unterteilt:"
1) Datenströme werden anhand ihrer Richtung unterteilt: Eingabedatenströme und Ausgabedatenströme
2) Streams werden anhand ihres Datentyps unterteilt: solche, die mit Bytes arbeiten und solche, die mit Zeichen arbeiten.
Hier siehst du diese Unterteilungen in einer Tabelle:
Eingabedatenstrom | Ausgabedatenstrom | |
---|---|---|
Arbeitet mit Bytes | InputStream | OutputStream |
Arbeitet mit Zeichen | Reader | Writer |
Wenn ein Objekt das InputStream-Interface implementiert, dann unterstützt es die Fähigkeit, Bytes sequentiell aus ihm zu lesen.
Wenn ein Objekt das OutputStream-Interface implementiert, dann unterstützt es die Fähigkeit, Bytes sequentiell in es hineinzuschreiben.
Wenn ein Objekt das Reader-Interface implementiert, dann unterstützt es die Fähigkeit, Zeichen (chars) sequentiell aus ihm zu lesen.
Wenn ein Objekt das Writer-Interface implementiert, dann unterstützt es die Fähigkeit, Zeichen (chars) sequentiell in es hineinzuschreiben.
Ein Ausgabedatenstrom ist wie ein Drucker. Wir können Dokumente zum Drucker ausgeben. Wir können Daten zu einem Ausgabedatenstrom ausgeben.
Ein Eingabedatenstrom kann seinerseits mit einem Scanner oder vielleicht einer Steckdose verglichen werden. Mit einem Scanner können wir Dokumente auf unseren Computer bringen. Oder wir können ein Gerät an einer Steckdose anschließen und von dort Strom erhalten. Wir können Daten aus einem Eingabedatenstrom erhalten.
„Wo werden sie eingesetzt?“
„Diese Klassen werden überall in Java verwendet. Unser guter Freund System.in ist eine statische InputStream-Variable mit dem Namen in in der Klasse System.“
„Ernsthaft?! Ich habe also die ganze Zeit einen InputStream verwendet und es nicht einmal bemerkt. Ist System.out dann auch ein Stream?“
„Ja, System.out ist eine statische PrintStream-Variable (ein Abkömmling von OutputStream) in der System-Klasse.“
„Willst du mir damit sagen, dass ich schon immer mit Streams gearbeitet habe und es einfach nur nicht wusste?“
„Ja, und das zeigt uns gerade, wie praktisch diese Datenströme sind. Man schnappt sich einfach einen und benutzt ihn.“
„Aber das kann man über System.in nicht sagen. Wir mussten ständig BufferedReader oder InputStreamReader einfügen.“
„Das stimmt. Aber dafür gab es auch Gründe.“
Es gibt eine Menge Datentypen und viele Möglichkeiten, mit ihnen zu arbeiten. So wuchs die Anzahl der Standard-E/A-Klassen sehr schnell, obwohl sie alles fast auf die gleiche Art und Weise gemacht haben. Um diese Komplexität zu vermeiden, haben Java-Entwickler das Prinzip der Abstraktion genutzt und die Klassen in viele kleine Teile aufgeteilt.
Aber du kannst diese Teile auf eine einheitliche Weise miteinander verbinden und so eine sehr komplexe Funktionalität erhalten, wenn du sie benötigst. Sieh dir dieses Beispiel an:
Eine Zeichenfolge auf der Konsole ausgeben |
|
Speichere den Konsolenausgabestrom in einer separaten Variable. Gib eine Zeichenfolge zum Stream aus. |
|
Erstelle ein dynamisches (expandierendes) Byte-Array im Speicher. Verbinde es mit einem neuen Ausgabestrom (PrintStream-Objekt). Gib eine Zeichenfolge zum Stream aus. |
|
„Das ist doch wie ein Lego-Bausatz. Nur ist mir nicht klar, was dieser Code bewirkt.“
„Mach dir darüber erstmal keine Gedanken. Alles zu seiner Zeit.“
Ich möchte, dass du dir folgendes merkst: Wenn eine Klasse das OutputStream-Interface implementiert, kannst du Bytes in sie hinein schreiben. Fast genauso, wie du Daten auf der Konsole ausgibst. Was sie damit macht, ist ihre Sache. Bei unserem „Lego-Bausatz“ ist uns der Zweck jedes einzelnen Teils egal. Uns interessiert nur, dass wir durch die große Auswahl an Teilen so coole Sachen bauen können.
„Okay. Wo fangen wir an?“
GO TO FULL VERSION