„Hallo Amigo! Ich möchte dir von zwei Interfaces erzählen: InputStream und OutputStream. Sie sind als abstrakte Klassen deklariert, aber wenn man genauer hinschaut, kann man erkennen, dass sie eigentlich Interfaces sind. Fast alle ihre Methoden sind abstrakt, bis auf einige wenige unbedeutende Methoden. Sie ähneln sehr dem „Bodyguard“, den wir bereits kennengelernt haben.“

Das sind sehr interessante Interfaces. Fürs Erste werde ich sie absichtlich „Interfaces“ nennen, damit du verstehst, warum wir sie brauchen. Später werden wir dann darüber sprechen, warum es tatsächlich abstrakte Klassen sind.

„Okay. Also, was sind diese Interfaces?“

„Ich werde es dir ohne Umschweife sagen.“

Java hat diese interessante Sache, die man „Stream“. Ein Stream ist ein sehr einfaches Gebilde. Tatsächlich ist seine Einfachheit der Schlüssel für eine sehr leistungsfähige Art des Datenaustauschs. Es gibt zwei Arten von Streams: Streams zum Lesen und Streams zum Schreiben.

Wie du wahrscheinlich schon erraten hast, kannst du Daten zum Schreiben in einen Stream schreiben. Dafür besitzt er eine write-Methode. Du kannst Daten zum Lesen aus einem Stream lesen. Dafür besitzt er eine read()-Methode.

InputStream ist das Interface für einen Stream, der den Lesevorgang unterstützt. Es definiert folgende Fähigkeit: „Bytes können von mir gelesen werden“.

Auf die gleiche Weise ist OutputStream ein Interface für einen Stream, der den Schreibvorgang unterstützt. Es definiert die folgende Fähigkeit: „Bytes können mir geschrieben werden“.

„Das war‘s?“

„Mehr oder weniger. Der entscheidende Punkt ist, dass Java viele Klassen besitzt, die mit InputStream und OutputStream arbeiten können. Willst du zum Beispiel eine Datei von der Festplatte lesen und ihren Inhalt auf dem Bildschirm anzeigen? Nichts einfacher als das.“

Um Daten aus einer Datei auf der Festplatte zu lesen, gibt es die spezielle Klasse FileInputStream, die das InputStream-Interface implementiert. Willst du diese Daten in eine andere Datei schreiben? Dafür steht uns die Klasse FileOutputStream zur Verfügung, die das Interface OutputStream implementiert. Der folgende Code zeigt dir, was du tun musst, um Daten von einer Datei in eine andere zu kopieren.

Code
public static void main(String[] args) throws IOException
{
 InputStream inStream = new FileInputStream("c:/source.txt");
 OutputStream outStream = new FileOutputStream("c:/result.txt");

 while (inStream.available() > 0)
 {
  int data = inStream.read(); //read one byte from the input stream
  outStream.write(data); //write that byte to the other stream.
 }

 inStream.close(); //close the streams
 outStream.close();
}

Stell dir vor, wir hätten eine Klasse geschrieben und ihr die Fähigkeiten InputStream und OutputStream gegeben.

Wenn wir diese Interfaces richtig implementiert haben, dann können nun Instanzen unserer Klasse in einer Datei gespeichert oder aus einer Datei gelesen werden. Und das ganz einfach durch das Lesen ihrer Inhalte mit der read-Methode. Oder sie können aus einer Datei geladen werden, indem wir ein Objekt erstellen und mit der write-Methode den Inhalt der Datei schreiben.

„Hast du vielleicht ein Beispiel?“

„Klar.“

Code Beschreibung
class MyClass
{
private ArrayList<Integer> list;
}
Stelle dir der Einfachheit halber vor, dass unsere Klasse ein Objekt enthält, eine ArrayList mit Integer-Werten.

Jetzt fügen wir noch die Lese- und Schreibmethoden read und write hinzu.

Code Beschreibung
class MyClass
{
private ArrayList<Integer> list;
public void write(int data)
{
list.add(data);
}
public int read()
{
int first = list.get(0);
list.remove(0);
return first;
}

public int available()
{
return list.size();
}
}
Nun implementiert unsere Klasse die read-Methode, mit der wir den gesamten Inhalt von list der Reihe nach lesen können.

Und die write-Methode, mit der wir Werte in unsere Liste schreiben können.

Natürlich ist das keine Implementierung der InputStream- und OutputStream-Interfaces, aber es ist ihnen sehr ähnlich.

„Ja, das verstehe ich. Wie speichert man also die Inhalte eines solchen Objekts in einer Datei?“

„Hier ein Beispiel für dich:“

Schreibe ein MyClass-Objekt in eine Datei
public static void main(String[] args)
{
 MyClass myObject = new MyClass();
 OutputStream outStream = new FileOutputStream ("c:/my-object-data.txt");

 while (myObject.available() > 0)
 {
  int data = myObject.read(); //read one int from the input stream
  outStream.write(data); //write that int to the other stream.
 }

 outStream.close();
}
Lies ein MyClass-Objekt aus einer Datei
public static void main(String[] args)
{
 InputStream inStream = new FileInputStream("c:/my-object-data.txt");
 MyClass myObject = new MyClass();

 while (inStream.available() > 0)
 {
  int data = inStream.read(); //read one int from the input stream
  myObject.write(data); //write that int to the other stream.
 }

 inStream.close(); //close the streams
}

„Heiliger Strohsack! Das sieht ja wirklich aus wie die Arbeit mit InputStream und OutputStream. Streams sind klasse!“

„Und noch einiges mehr!“