Freitag, 23. August 2019

Textdateien Zeile für Zeile lesen

Einfache Textdateien mögen auf den ersten Blick etwas mittealterlich wirken, aber sie werden dennoch häufig bei der Programmentwicklung verwendet. Es ist eben leicht, einfachen Text in diesen Dateien unterzukriegen und deswegen sollte man sie nicht unterschätzen. Eine besondere Form, die properties-Dateien, stelle ich in einem anderen Beitrag vor.

Die Frage ist jetzt wie wir in eine Textdatei schreiben und wieder aus ihr lesen. In diesem Beitrag beschäftigen wir uns mit dem Lesen.

Die ganze Datei in den Arbeitsspeicher laden

Für kleine Dateien ist dies eine ganz gute Methode: Wir klatschen einfach den Inhalt der kompletten Textdatei in den Arbeitsspeicher. Das sieht dann so aus wie im folgenden Beispiel zu sehen:

public static void printTextFileOnScreen(String fileName) {
    Path path = Paths.get(fileName);
    List<String> lines = Files.readAllLines(path);
    for (String line : lines) {
       System.out.println(line);
    }

}

Dieser Code lädt die gesamte Textdatei in den Arbeitsspeicher und die Zeilen in ein String-Array. Dann wird das Array durchlaufen und jede Zeile der Textdatei wird ausgegeben. Der Code ist einfach und knackig. Der Nachteil liegt auch auf der Hand und wurde schon erwähnt: Für größere Dateien ist diese Vorgehensweise absolut ungeeignet, da wir die komplette Datei in den Arbeitsspeicher laden.

BufferedInputReader


Obwohl die vorherige Methode für kleine Dateien durchaus anwendbar ist, möchte ich dennoch empfehlen, den im folgenden vorgestellten BufferedInputReader immer zu verwenden. Denn wie genau definiert sich eine Datei als "klein"? Aber sehen wir uns erst einmal ein bisschen Code an.

public static void printFileOnScreen(String filename) {
    BufferedReader bufferedReader = null;
   
    try {
        bufferedReader = new BufferedReader(new FileReader(filename));
        String line = null;
       
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
    } catch (FileNotFoundException ex) {
        ex.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}


Als erstes fällt auf, dass wir erheblich mehr schreiben müssen. In einem anderen Beitrag werde ich noch eine Möglichkeit vorstellen, wie man diese Menge an Boilerplate-Code etwas reduzieren kann. Was geschieht hier? Wir erzeugen als erstes ein FileReader-Objekt, mit dem wir auf die Datei zugreifen. FileReader stellt nur die absoluten Basisfunktionen zur Verfügung und aus diesem Grund stecken wir ihn in einen BufferedReader, dessen Interface umfangreicher ist. Dann laufen wir in einer Schleife durch die Datei. In jedem Schleifendurchlauf holen wir uns mit readLine() die aktuelle Zeile.

Im Gegensatz zu der vorherigen Lösung haben wir also immer nur die aktuelle Zeile im Arbeitsspeicher. Die Schleife läuft, solange wir noch Zeilen lesen. Wenn wir die letzte Zeile erreicht haben, gibt readLine() null zurück und die Schleife wird beendet. Vergessen Sie nicht, das BufferedReader-Objekt am Ende wieder brav zu schließen. 

Keine Kommentare:

Kommentar veröffentlichen