Daten in eine Datei schreiben

Nachdem wir nun Daten aus einer Datei lesen können, wäre es nicht schlecht die Daten auch wieder in eine Datei schreiben zu können. Im Prinzip machen wir dazu dasselbe wie zum lesen. Die Datei wird geöffnet, es wird ein Kanal erzeugt, der in eine Datei schreiben kann, die Daten werden in die Datei geschrieben und die Datei wird geschlossen.

Wie zu erwarten war, heißen die zum Schreiben benötigten Objekte und Methoden nicht mehr Reader, sondern Writer. Wir hatten zum Lesen einer Datei die Klassen FileReader und BufferedReader benutzt, zum Schreiben benutzen wir FileWriter und BufferedWriter.

Um zusätzliche Verwirrung zu verursachen, habe ich auch noch einige der gewohnten Dinge in unserem Programm geändert. Zum Beispiel, habe ich die einzelnen Vorgänge aus dem Konstruktor der Klasse Kaffeetassen entfernt, den Konstruktor gelöscht und dafür jeweils eine Methode zum Lesen, Ausgeben und Speichern der Daten erzeugt. Eine weitere Methode legt eine neue Tasse an.
Der Vorteil davon ist, dass die zukünftigen Erweiterungen auf diese Methoden zugreifen, ohne das darin Änderungen gemacht werden müssen.
Die Klasse Tassen wurde ebenfalls um zwei neue Methoden "hinzufügen" und "löschen" erweitert. Wobei "löschen" im Moment noch nicht verwendet wird.

Da wir die Daten jetzt auch bearbeiten wollen, zum Beispiel eine neue Tasse zu unseren Daten hinzufügen, führe ich eine neue Klasse LinkedList ein. Diese Klasse erlaubt es, Daten in einer Liste zu speichern. OK, kommt der Einwand, das kann ein Array aber auch. Ja, ein Array kann das auch, aber, bei einem Array muss ich vorher wissen wie viele Elemente ich haben werde. Eine LinkedList kann beliebig viele Elemente aufnehmem und ich kann mich in der Liste mit den Methoden next und previous, also nächste und vorhergehende Zeile, frei bewegen.

Sehen wir uns die erste Methode im Kaffeetassen Programm an:


                 import java.util.*;
                 import java.io.*;

                 class Kaffeetassen {

                         /* Programm Kaffeetassen von Heiko Schmuck, im April 2011
                         * Das Programm beschreibt Kaffetassen und gibt die Beschreibung
                         * auf dem Bildschirm aus.
                         * In der zehnten Version werden die Daten aus einer Datei gelesen.
                         * Es können neue Tassen eingegeben werden.
                         * Zum Zwischenspeichern der Tassen werden Listen benutzt
                         * Die Tassen können in einer Datei gespeichert werden.
                         */

                         /* Methode um Kaffeetassen aus einer Datei zu lesen
                         * dp ist der Dateipfad als String
                         * tl ist die Liste der Tassen.
                         */

                         void DateiLesen(LinkedList tl, String dp) throws IOException {

                                 // In diese Variablen kommen die Eigenschaften der Tasse.
                                 String f, he, a;
                                 int h, d;
                                 Tasse t;

                                 System.out.println("Datei lesen");
                                 System.out.println("--------------------------------");

                                 //Das Datei-Objekt erzeugen
                                 FileReader Datei = new FileReader(dp);

                                 //Die Datei öffnen und einen Input Stream für die Datei erzeugen
                                 BufferedReader din = new BufferedReader(Datei);

                                 //Die Zeilen in einer FOR-Schleife einlesen
                                 for(String zeile = din.readLine(); zeile != null; zeile = din.readLine()){
                                         StringTokenizer data = new StringTokenizer(zeile, ",");

                                         //Die Eigenschaften in Variablen ablegen
                                         f = data.nextToken();
                                         h = new Integer(data.nextToken());
                                         d = new Integer(data.nextToken());
                                         he = data.nextToken();
                                         a = data.nextToken();

                                         //Das Objekt Tasse erzeugen und ausgeben.
                                         t = new Tasse(f, h, d, he, a);
                                         t.hinzufuegen(tl);
                                 }

                                 //Datei schließen
                                 din.close();

                                 System.out.println("--------------------------------");
                         }
                 [...]

Im Prinzip gibt es hier nicht viel neues. Der Methode werden zwei Parameter übergeben, die LinkedList in der die Daten gespeichert werden und der Pfad zur Datei aus der gelesen werden soll. Neu ist die Methode t.hinzufuegen(tl);, die die Tasse der Liste hinzufügt. Diese Methode gehört zur Klasse Tasse, das heißt, jedes Objekt vom Typ Tasse kann sofort darauf zugreifen.


                 [...]
                         void hinzufuegen (LinkedList l) {
                                 l.add(this);
                                 System.out.println("Tasse hinzugefügt");
                         }
                 [...]

Diese Methode macht nichts anderes, als die aktuelle Tasse mit l.add(this); zur Liste LinkedList l hinzuzufügen. this ist ein Schlüsselwort, welches man benutzen kann, um innerhalb einer Methode das aktuelle Objekt anzusprechen.

Die nächste Methode legt eine neue Tasse an. Auch hier gibt es nicht viel neues.


                 [...]
                         void NeueTasse(LinkedList tl) throws IOException {

                                 // In diese Variablen kommen die Eigenschaften der Tasse.
                                 String f, he, a;
                                 int h, d;
                                 Tasse t;

                                 // Variable für die Antwort
                                 String e;

                                 // Hier wird die Tastatureingabe eingebunden
                                 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

                                 // Abfragen ob eine neue Tasse eingegeben werden soll
                                 System.out.println("Möchten Sie eine neue Tasse eingeben? J oder N eingeben.");
                                 e = in.readLine();      // Wartet auf eine Eingabe, die Eingabe wird mit Enter abgeschlossen.

                                 // Nach der Eingabe prüfen ob ein "J" eingegeben wurde, ansonsten diesen Teil überspringen.
                                 if(e.equals("J")) {

                                         // Die Eigenschaften der neuen Tassen eingeben
                                         System.out.println("Farbe?");
                                         f = in.readLine();
                                         System.out.println("Höhe?");
                                         h = new Integer(in.readLine()).intValue();
                                         System.out.println("Durchmesser?");
                                         d = new Integer(in.readLine()).intValue();
                                         System.out.println("Henkel?");
                                         he = in.readLine();
                                         System.out.println("Aufdruck?");
                                         a = in.readLine();

                                         // Neue Tasse anlegen
                                         t = new Tasse(f, h, d, he, a);

                                         // Die neue Tasse ausgeben
                                         System.out.println("--------------------------------");
                                         t.hinzufuegen(tl);
                                         System.out.println("--------------------------------");
                                         System.out.println();
                                 }
                         }
                 [...]

Auch hier benutzen wir wieder die Methode t.hinzufuegen(tl);. Ansonsten wieder nichts neues.

Endlich kommen wir zu der Stelle an der die LinkedList benutzt wird. Die Methode TassenAusgeben greift zum lesen der Tassen auf die Liste zu.


                 [...]
                         void TassenAusgeben(LinkedList tl) {

                                 // Erst einmal eine Überschrift
                                 System.out.println("Meine Kaffeetassen:");
                                 System.out.println("--------------------------------");

                                 Tasse t;

                                 for (ListIterator l = tl.listIterator();l.hasNext();) {
                                         t = (Tasse) l.next();
                                         t.ausgeben();
                                 }
                         }
                 [...]

Der Methode wird die LinkedList übergeben. In der for-Schleife wird dann ein ListIterator erzeugt, mit dem man sich durch die Liste bewegen kann. Der ListIterator hat eine Methode l.hasNext();. Diese Methode gibt zurück, ob es ein weiteres Element in der Liste gibt. Mit t = (Tasse) l.next(); holen wir uns das nächste Listenelement und sagen dem Programm, dass die Elemente vom Typ Tasse sind. Machen wir das nicht, nimmt das Programm den Typ Object, mit dem wir nicht viel anfangen können. Zum Schluß benutzen wir t.ausgeben();, um die Tassen auf dem Bildschirm auszugeben.

In der letzten Methode werden die Tassen der Liste in einer Datei gespeichert.


                 [...]
                         void TassenSpeichern(LinkedList tl, String dp) throws IOException {

                                 //Das Dateiobjekt erzeugen
                                 FileWriter Datei = new FileWriter(dp);

                                 //Die Datei öffnen und einen Output Stream für die Datei erzeugen
                                 BufferedWriter dout = new BufferedWriter(Datei);

                                 Tasse t;
                                 String zeile;
                                 String neueZeile = System.getProperty("line.separator");

                                 for (ListIterator l = tl.listIterator();l.hasNext();) {
                                         t = (Tasse) l.next();
                                         zeile = t.farbe + "," + String.valueOf(t.hoehe) + "," + String.valueOf(t.durchmesser) + "," + t.henkel + "," + t.aufdruck + neueZeile;
                                         dout.write(zeile);
                                         System.out.println("--------------------------------");
                                         System.out.println("Tasse gespeichert");
                                         System.out.println("--------------------------------");
                                 }
                                 dout.close();
                         }
                 [...]

Wenn man diese Methode mit der Methode DateiLesen vergleicht, findet man einige Gemeisamkeiten. Anstatt FileReader und BufferedReader, werden FileWriter und BufferdWriter benutzt. Ansonsten ähneln sich die beiden Methoden doch sehr. Mit FileWriter Datei = new FileWriter(dp); wird die Datei zum Schreiben vorbereitet, danach kann mit BufferedWriter dout = new BufferedWriter(Datei); in die Datei geschrieben werden.
String neueZeile = System.getProperty("line.separator"); holt sich vom System das Zeichen, das für eine neue Zeile benutzt wird. Dieses Zeichen benötigen wir am ende der Zeile, um einen Zielenvorschub zu erzeugen. Ohne Zeilenvorschub werden die Elemente einfach hintereinander in eine Zeile geschrieben.
Mit dout.write(zeile); wird die Zeile zeile = t.farbe + "," + String.valueOf(t.hoehe) + "," + String.valueOf(t.durchmesser) + "," + t.henkel + "," + t.aufdruck + neueZeile; in die Datei geschrieben. Nicht vergessen mit dout.close(); die Datei wieder zu schließen.
Die Methode String.valueOf(t.hoehe) wandelt den int-Wert in einen String, da dout.write(zeile); nur Strings verarbeiten kann.

Zum Schluß werden die Methoden in unserer main-Methode aufgerufen.


                 [...]
                         public static void main (String [] args) throws IOException {

                                 // Der Pfad zur Datei
                                 String P = "C:\\justfun\\Tassen.txt";

                                 // Das Objekt Kaffeetassen erzeugen
                                 Kaffeetassen K = new Kaffeetassen();

                                 // Ein Listenobjekt für die Tassen erzeugen.
                                 LinkedList T = new LinkedList();

                                 K.DateiLesen(T,P);
                                 K.NeueTasse(T);
                                 K.TassenAusgeben(T);
                                 K.TassenSpeichern(T, P);


                         }
                 [...]

Die Variablen P, K, T enthalten den Pfad zur Datei, unsere Klasse Kaffeetassen, um die Methoden aufrufen zu können und die LinkedList, um die Daten zu Speichern.

Das Programm "am Stück" gibt es hier.

Weiter geht es mit Grafik in JAVA

Mit JAVA programmieren

Als Entwicklungsumgebung benutze ich NetBeans 7.