Java Getriebe

Java und NetBeans

Daten einlesen und schreiben

Im Leben ist alles im Fluss. In Java ist alles ein Strom. Ein Datenstrom. Um genau zu sein ein InputStream bzw. OutputStream. Zumindest trifft dies auf den Bereich von Java zu, wo es um den Datentransfer geht. Damit ist der Datentransfer von einer Datei in den Hauptspeicher oder umgekehrt gemeint. Genauso wie der Datentransfer von einem Webserver auf die lokale Festplatte. Der Datentransfer kann sogar ein Java Objekt sein, welches vom Client zum Server kopiert wird. Datenströme müssen aber nicht zwingend nur mit Dateien auf Festplatten oder Webservern zu tun haben.

Für den Java Entwickler ist nur Interessant, dass er sich mit einem Datenstrom beschäftigt. Wo dieser Datenstrom her kommt oder wo er mal hin geht spielt meistens eine Untergeordnete Rolle. An dieses Konzept muss man sich einmal gewöhnt haben, dann sind die folgenden Quellbeispiele eigentlich kein Problem mehr.

Daten lesen

Natürlich liegen die Datenströme in Java nicht einfach so in der Landschaft rum. Sie müssen natürlich an einer bestimmten Stelle einmal erzeugt werden. Um zum Beispiel eine beliebige Datei in einen solchen Datenstrom zu verwandeln wird die Klasse FileInputStream verwendet um einen solchen InputStream zu erhalten:

1
2
File datei = new File("eingabedatei.dat");
InputStream in = new FileInputStream(datei);

Das Problem an der Stelle jetzt ist, dass wir relativ schlecht an die Daten heran kommen. Sie müssten jedes Byte einzeln (oder in ein byte Array) eingelesen werden und entsprechend im eigenen Programm wieder zusammengesetzt werden. In den allermeisten Fällen ist das aber übertrieben. Aus diesem Grund gibt es diverse Implementierungen, wie von InputStream ableiten und diesen durch „spezifischere“ Einleseroutinen ergänzen.

Ein DataInputStream kann die Daten zum Beispiel direkt in einen Java Zahlentyp (wie int, double, float etc.) umwandeln, ohne dass man sich als Entwickler weiter Gedanken machen muss. Schaut man sich den Konstruktor einmal genauer an, so kann man vielleicht schon erahnen, warum das so toll ist in Java nur mit InputStreams zu arbeiten. Um einen DataInputStream zu bekommen benötigt man einen anderen InputStream. Nur die Basisklasse allen Datentransfers. Dem DataInputStream ist es also egal, ob man jetzt aus einer Datei oder einem byte Array lesen möchte. Egal ob die Daten auf der Festplatte, im Speicher oder auf einem entfernten Rechner vorliegen. Die Klasse wandelt nur einen beliebigen Datenstrom um so dass man ein double oder int daraus interpretieren kann.

1
2
3
4
5
6
7
File datei = new File("eingabedatei.dat");
InputStream in = new FileInputStream(datei);
DataInputStream data = new DataInputStream(in);

double wert1 = data.readDouble();
int wert2 = data.readInt();
String text1 = data.readUTF();

Wie DataInputStream haben auch die meisten anderen InputStreams einen Konstruktor der ein InputStream verlangt. So kann man sich nahezu beliebig Datenströme „zurecht biegen“, wie man sie gerne hätte. Es ist quasi total egal, wo die Daten tatsächlich her kommen, solange sie in einen InputStream verpackt wurden.

Daten schreiben

Auch das schreiben der Daten funktioniert nach einem ähnlichen Prinzip. Auch hier gibt es Klassen, die von OutputStream abgeleitet sind und entweder das Schreibziel definieren (FileOutputStream) oder die Art und Weise, wie man Daten in den Strom einspeisen möchte (DataOutputStream). Letzere sind wie auch schon beim Lesen dazu geeignet einen anderen OutputStream aufzunehmen und diesem die Daten passend aufbereitet zu übermitteln.

1
2
3
4
5
6
7
File datei = new File("ausgabedatei.dat");
OutputStream in = new FileOutputStream(datei);
DataOutputStream data = new DataOutputStream(in);

data.writeDouble(3.14);
data.writeInt(42);
data.writeUTF("Hallo Welt");

Streams vs. Reader/Writer

In Java gibt es noch zwei weitere Klassen, die für Ein- und Ausgabe zuständig sind: Reader und Writer. Im Gegensatz zu den Datenströmen bei denen binäre Daten mit beliebigem Inhalt verarbeitet werden geht es bei den beiden hier explizit um Textdaten. Also Buchstaben, Zahlen und sonstige Zeichen, die man in der Grundschule beigebracht bekommt.

Das Prinzip ist auch hier das gleiche wie bei den allgemeinen Datenströmen. Reader lesen ein, Writer schreiben raus. Es gibt FileReader, LineNumberReader oder auch StringReader. PrintWriter zum Beispiel eignen sich sehr gut um Zeilenweise Textdaten zu schreiben. Außerdem ist es möglich einen InputStream mit Hilfe des InputStreamReader in einen Reader umzuwandeln (analog mit OutputStream und Writer) um Texte aus Datenströmen auszulesen.

Wofür brauche ich das?

Wie Anfangs bereits geschrieben. Daten Ein- und Ausgabe unter Java ist keine Hexerei mehr, wenn man sich einmal mit dem Konzept der „verschachtelten“ Klassen angefreundet hat. Es gibt I/O-Klassen, die den Ursprung definieren und welche die das Format der Daten beschreiben. Diese müssen nur nach eigenen Wünschen kombiniert werden und schon sind die Daten wie geplant an der richtigen Stelle.