„Wir beginnen mit Streams für die Dateieingabe und Dateiausgabe. Aber eins nach dem anderen.“

Es gibt zwei Klassen zum Lesen und Schreiben von Dateien: FileInputStream und FileOutputStream. Wie du wahrscheinlich schon erraten hast, kannst du mit FileInputStream Bytes nacheinander aus einer Datei lesen und mit FileOutputStream Bytes nacheinander in eine Datei schreiben. Hier siehst du die Methoden, die diese Klassen besitzen:

Methode Das tut die Methode
FileInputStream(String fileName);
– Das ist der Konstruktor. Hier kannst du den Namen einer Datei auf der Festplatte angeben, aus der das erzeugte Objekt Daten lesen wird.
int read();
– Diese Methode liest ein Byte aus der Datei und gibt es zurück. Der Rückgabewert wird auf ein int erweitert.
int available();
– Diese Methode gibt die Anzahl der ungelesenen (verfügbaren) Bytes zurück.
void close();
– Mit dieser Methode wird der Datenstrom „geschlossen“. Du rufst sie auf, wenn du die Arbeit mit dem Stream beendet hast.
Das Objekt führt dann die notwendigen Operationen aus, um die Datei zu schließen usw.
Zu diesem Zeitpunkt kannst du keine Daten mehr aus dem Stream lesen.

Nur so zum Spaß berechnen wir die Summe aller Bytes in einer Datei. So sieht der Code aus:

Alle Bytes in einer Datei summieren
public static void main(String[] args) throws Exception
{
 //Erstelle ein FileInputStream-Objekt für „c:/data.txt“
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 long sum = 0;

 while (inputStream.available() > 0) //solange es ungelesene Bytes gibt
 {
  int data = inputStream.read(); //Lies das nächste Byte
  sum +=  data; //Zur aktuellen Gesamtsumme addieren
 }
 inputStream.close(); // Stream schließen

 System.out.println(sum); // Summe auf dem Bildschirm anzeigen
}

„Wir haben uns bereits mit so etwas beschäftigt. Wie ist FileOutputStream aufgebaut?“

„OK. Sieh dir das an:“

Methode Das tut die Methode
FileOutputStream (String fileName);
„Das ist der Konstruktor. Hier kannst du den Namen einer Datei auf der Festplatte angeben, in die das erzeugte Objekt Daten schreiben wird.
void write(int data);
„Diese Methode schreibt das nächste Byte, wobei die Daten auf ein Byte abgeschnitten werden.“
void flush();
„Die zu schreibenden Daten werden oft zuerst in großen Blöcken im Speicher gesammelt und dann erst auf die Festplatte geschrieben.“

Der flush-Befehl erzwingt, dass alle ungespeicherten Informationen auf die Festplatte geschrieben werden.

void close();
„Diese Methode ‚schließt‘ den Datenstrom. Du rufst sie auf, wenn du die Arbeit mit dem Stream beendet hast.“
Das Objekt führt dann die notwendigen Operationen aus, um die Datei zu schließen usw.

Du kannst keine Daten mehr in den Stream schreiben, und flush wird automatisch aufgerufen.

„Das war‘s?“

„Ja, es gibt tatsächlich nur eine Methode zum Schreiben: write(). Sie schreibt jeweils nur ein Byte auf einmal. Aber du kannst so viele Informationen in die Datei schreiben, wie du willst.“

Beim Programmieren geht es darum, eine große und komplexe Aufgabe in viele kleine Aufgaben aufzuteilen. Im Wesentlichen geschieht hier genau das: Das Lesen und Schreiben großer Datenblöcke wird in Bit-große Teile aufgeteilt – jeweils ein Byte auf einmal.

So kannst du diese Klassen verwenden, um eine Datei auf die Festplatte zu kopieren:

Eine Datei auf die Festplatte kopieren
public static void main(String[] args) throws Exception
{
 //Erstelle einen Stream zum Lesen von Bytes aus einer Datei
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 //Erstelle einen Stream zum Schreiben von Bytes in eine Datei
 FileOutputStream outputStream = new FileOutputStream("c:/result.txt");

 while (inputStream.available() > 0) //solange es ungelesene Bytes gibt
 {
  int data = inputStream.read(); //Lies das nächste Byte in die data-Variable
  outputStream.write(data); // und schreibe es in den zweiten Stream
 }

 inputStream.close(); //Beide Streams schließen Wir brauchen sie nicht mehr.
 outputStream.close();
}

„Danke, Ritschie. Endlich verstehe ich, wie dieser Code tatsächlich funktioniert.“