22 Datenströme
22.1 Einfache Input- und Outputströme
 
System.out und System.in Ein Rechnersystem besitzt zwei Standartströme. Da ist zunächst der Standard-Ausgabestrom, der Daten z.B. zum  Bildschirm transportiert; als Ziel kann aber auch ein anderes 'Gerät' gewählt werden. Dann haben wir einen Standart-Eingabestrom, er kommt in der Regel von der Tastatur; auch hier kann als Quelle ein anderes 'Gerät' angegeben werden. Diese Standardströme stellt uns das Rechnersystem grundsätzlich zur Verfügung, sie sind also immer 'geöffnet', und Java ist daran nicht beteiligt.  Wir wollen in diesem Abschnitt nun lernen, wie Java diese Ströme nutzt, um Daten aus einer Anwendung heraus an den Bildschirm zu senden, bzw. Daten, die über eine Tastatur eingegeben sind, für eine weitere Verwendung liest. Es ist ganz hilfreich, die Datenströme als eine Art Pipeline vorzustellen, in die auf der einen Seite Daten eingespeist und auf der anderen Seite entnommen werden. Sie werden in Java als Objekte der Klassen PrintStream bzw. InputStream dargestellt. Die Klasse System stellt uns Referenzen von PrintStream bzw. InputStream  in Form der Klassenobjekte System.out und System.in zur Verfügung. Die Klasse System gehört zum Paket java.lang, das standardmäßig in jede Klasse eingebunden ist; ein Import von java.lang ist deshalb nicht nötig.

Um nun Daten aus einem Javaprogramm in die Ausgabe-Pipeline zu speisen stellt die Klasse PrintStream ihren Referenzen eine Reihe Methoden zur Verfügung (Siehe Auszug aus der Java-Spezifikation):


So speist ein Javaprogramm mit
System.out.println("Hallo Welt") die Ausgabe-Pipeline mit der Zeichenkette 'Hallo Welt'. Auf der anderen Seite der Pipeline entnimmt das System die Daten als Folge von bytes, die das System auf dem Bildschirm als Folge von Zeichen darstellt. das Ergebnis kennen wir von dem bekannten "Hallo Welt*-Programm.
 

Ausgabe auf Bildschirm
public class AusgabeStrom {

  public static void main (String[] args) {
    System.out.println("Hallo Welt");
  }
}
  Entsprechendes gilt für die Eingabe-Pipeline. Das System speist Daten auf der anderen Seite ein und Java entnimmt dieser Pipeline, die es als System.in kennt, die Daten. Zur Organisation dieser Entnahme stellt die Klassen InputStream ihren Referenzen Methoden wie z.B.  read() zur Verfügung.

 

Die read()-Methode Wie arbeitet nun die read()-Methode genauer? Zunächst hält die Methode read() den Ablauf des aufrufenden Programms an, prüft, ob in der Pipeline Daten sind und gibt, falls welche vorhanden sind den ersten byte-Block als int an das aufrufende Programm. Ist die Pipeline dagegen leer, so bleibt das Programm solange angehalten, bis das System die Pipeline mit Daten gefüllt hat. Abgeschlossen wird die Eingabe durch einen bestimmten Code, der durch das Drücken der Eingabetaste erzeugt wird. Jetzt erst liest die read()-Methode den ersten 1 Byte großen Block aus der Pipeline und liefert ihn als ein int-Wert an das aufrufende Programm.

Das Lies1-Programm demonstriert diesen Sachverhalt:
 

Download:
Lies1.java
import java.io.*;
public class Lies1 {
  public static void main(String[] args) throws IOException1){
    int i = System.in.read();
    System.out.print(i);
  }
}
  Beim Starten des Programms, zeigt sich ein leeres Eingabefenster mit einem blinkenden Cursor. Die read()-Methode hat das Programm lies1 angehalten, da die Eingabe-Pipeline leer ist. Über Tastatur geben wir 'Java ist toll' ein. Nach dem Drücken einer Taste erscheint als Echo der entsprechende Buchstabe auf dem Bildschirm. Diese Ausgabe hat mit dem Javaprogramm nichts zu tun. Erst wenn nach dem Punkt die Eingabetaste gedrückt wird, übernimmt die das Programm lies1 wieder die Kontrolle über den Rechner und read() setzt seine Arbeit fort und das heißt es liest aus der Pipeline den ersten 1 Byte großen Block und liefert ihn als int-Wert an das Programm, das den Wert in der Variablen i speichert. System.out.print(i) speist die Ausgabe-Pipeline mit dem Wert. Das System entnimmt den Wert der Pipeline und stellt ihn auf dem Bildschirm dar. Wir erhalten somit folgende Darstellung:
 
  Java ist toll.
74
 
  Die vom System ausgegebene Zahl 74 ist nicht anderes als der ASCII-Code des Zeichens 'J'. Die Methode read() hat der Eingabe-Pipeline den Block 1001010 (Binärdarstellung von 74) entnommen und print(i) hat ihn in den Ausgabe-Pipeline gespeist. Es wundert also nicht, dass nur 74 ausgegeben wurde.

Wie erreicht man es aber, dass man dem Eingabestrom, der ja mehr enthält auch mehr entnimmt. Das Programm lies2 demonstriert dies.
 

Download:
Lies2.java
import java.io.*;
public class Lies2 {
  public static void main(String[] args) throws IOException1){
    int i;
    for (int j=0; j<10; j++){
      i = System.in.read();
      System.out.print(i+" ");
    }
  }
}
  Java ist toll.
74 97 118 97 32 105 115 116 32 116
 
  Beim Einstieg in die for-Schleife erkennt read() dass, die Eingabe-Pipeline leer ist, hält das Programm, übergibt an das System die Kontrolle um eine Eingabe zu erlauben. Nach dem Drücken der Eingabetaste übernimmt wieder das Java-Programm und die read()-Methode liest den ersten 1 Byte großen Block aus der Eingabe-Pipeline, der als int wieder in der Variablen i abgelegt wird. Wie schon im Beispiel lies1 wird 74 ausgegeben. Beim zweiten Schleifendurchgang registriert read(), dass die Eingabe-Pipeline Daten enthält und liest, ohne das Programm anzuhalten den nächsten 1 Byte großen Block, der dann als 97 ausgegeben wird. Es ist also klar dass 10 int- Werte ausgegeben werden. Es lässt sich leicht nachprüfen, dass es sich um den ASCII-Code der ersten 10 eingegeben Zeichen 'J', 'a', 'v', 'a', ' ', 'i', 's', 't', ' ', 't' handelt. (vgl. Kapitel 21.2).
   

1)

 

Die Methode read() kann u.U. eine Ausnahme verursachen, die man mit einer try und catch - Konstruktion verwalten müsste. Die Ausnahmebehandlung kann man aber dem Aufrufer der Klasse, das ist in diesem Falle die VM, delegieren, dies geschieht, in dem man das IOException-Objekt das in diesem Fall erzeugt wird, mit throws an den Aufrufer übergibt. Da die IOException-Klasse im Paket java.io liegt, muss dieses auch importiert werden. [zurück zu lies1.java] [zurück zu lies2.java]
   
zu 22.2 Die Klassen DataInputStream und DataOutputStream
zur Startseite www.pohlig.de  (C) MPohlig 2003