Part 4

Dateien und das Lesen von Daten

Ein beträchtlicher Teil der Software basiert in irgendeiner Form auf der Verarbeitung von Daten. Software, die zum Abspielen von Musik erstellt wurde, verarbeitet Musikdateien, und solche, die für die Bildbearbeitung erstellt wurden, verarbeiten Bilddateien. Anwendungen, die im Internet und auf mobilen Geräten laufen, wie Facebook, WhatsApp und Telegram, verarbeiten Benutzerinformationen, die in dateibasierten Datenbanken gespeichert sind. Allen diesen Anwendungen ist gemeinsam, dass sie Daten in irgendeiner Form lesen und verarbeiten. Die verarbeiteten Daten werden letztlich in irgendeinem Format in einer oder mehreren Dateien gespeichert.

Lesen von der Tastatur

Wir haben seit Beginn dieses Kurses die Scanner-Klasse verwendet, um Benutzereingaben zu lesen. Der Block, in dem Daten gelesen werden, war eine while-true-Schleife, bei der das Lesen bei einer bestimmten Eingabe endet.

Scanner scanner = new Scanner(System.in);

while (true) {
    String line = scanner.nextLine();

    if (line.equals("end")) {
        break;
    }

    // add the read line to a list for later
    // handling or handle the line immediately

}

Im obigen Beispiel übergeben wir den Systemeingabe (System.in, auch Standardeingabe) als Parameter an den Konstruktor der Scanner-Klasse. In textbasierten Benutzeroberflächen wird die Eingabe des Benutzers zeilenweise in den Eingabestrom geleitet, was bedeutet, dass die Information jedes Mal zur Verarbeitung gesendet wird, wenn der Benutzer eine neue Zeile eingibt.

Loading

Die Benutzereingabe wird in String-Form gelesen. Wenn wir die Eingabe beispielsweise als Ganzzahlen verarbeiten möchten, müssen wir sie in eine andere Form umwandeln. Ein Beispielprogramm ist unten bereitgestellt - es liest die Eingabe des Benutzers, bis der Benutzer "end" eingibt. Solange die Benutzereingabe nicht "end" ist, werden die Eingaben als Ganzzahlen verarbeitet - in diesem Fall wird die Zahl einfach ausgegeben.

Scanner scanner = new Scanner(System.in);

while (true) {
    String row = scanner.nextLine();

    if (row.equals("end")) {
        break;
    }

    int number = Integer.valueOf(row);
    System.out.println(row);
}
Loading

Dateien und das Dateisystem

Dateien sind Datensammlungen, die auf Computern gespeichert sind. Diese Dateien können unter anderem Text, Bilder, Musik oder eine Kombination davon enthalten. Das Dateiformat bestimmt den Inhalt der Datei sowie das Programm, das zum Lesen der Datei erforderlich ist. Beispielsweise werden PDF-Dateien mit einem Programm gelesen, das zum Lesen von PDF-Dateien geeignet ist, und Musikdateien werden mit einem Programm gelesen, das zum Lesen von Musikdateien geeignet ist. Jedes dieser Programme wurde von Menschen erstellt, und die Ersteller dieser Programme - also Programmiererinnen und Programmierer - legen im Rahmen ihrer Arbeit auch das Dateiformat fest.

Computer verfügen über verschiedene Programme zum Durchsuchen von Dateien. Diese Programme sind betriebssystemspezifisch. Alle Programme, die zum Durchsuchen von Dateien verwendet werden, nutzen in irgendeiner Weise das Dateisystem des Computers.

Eine Entwicklungsumgebung bietet uns üblicherweise die Möglichkeit, die Dateien eines Projekts zu durchsuchen. In IntelliJ können Sie sich alle Dateien anzeigen lassen, die mit einem Projekt verbunden sind, indem Sie das Project Tool mit alt + 1 bzw cmd + 1 (macOS) öffnen. Im Projekt Tool können Sie die Ansicht anpassen (Project: Zeigt die Projektdateien in der Standard-Ordnerstruktur, Packages: Zeigt die Dateien in einer paketbasierten Ansicht und File Explorer: Zeigt alle Dateien unabhängig von der Paketstruktur).

Loading

Das Lesen einer Datei

Das Lesen einer Datei erfolgt mithilfe der Scanner-Klasse. Wenn wir eine Datei mithilfe der Scanner-Klasse lesen möchten, geben wir den Pfad zu der Datei, die wir lesen möchten, als Parameter an den Konstruktor der Klasse. Der Pfad zur Datei kann mit dem Paths.get-Befehl von Java ermittelt werden, dem der Dateiname als Zeichenkette übergeben wird: Paths.get("filename.extension").

Wenn das Scanner-Objekt, das die Datei liest, erstellt wurde, kann die Datei mithilfe einer while-Schleife gelesen werden. Das Lesen wird fortgesetzt, bis alle Zeilen der Datei gelesen wurden, d.h. bis der Scanner keine weiteren Zeilen mehr findet. Das Lesen einer Datei kann zu einem Fehler führen, und aus diesem Grund erfordert der Prozess separate Blöcke - einen für das try und einen, um potenzielle Fehler zu catchen. Wir werden später im Kurs auf das Thema Fehlerbehandlung zurückkommen.

// zuerst
import java.util.Scanner;
import java.nio.file.Paths;

// im Programm:

// wir erstellen einen Scanner zum Lesen der Datei
try (Scanner scanner = new Scanner(Paths.get("file.txt"))) {

    // wir lesen die Datei, bis alle Zeilen gelesen wurden
    while (scanner.hasNextLine()) {
        // wir lesen eine Zeile
        String row = scanner.nextLine();
        // wir geben die gelesene Zeile aus
        System.out.println(row);
    }
} catch (Exception e) {
    System.out.println("Error: " + e.getMessage());
}

Eine Datei wird standardmäßig aus dem Projektstamm gelesen (wenn new Scanner(Paths.get("file.txt")) aufgerufen wird), d.h. aus dem Ordner, der den Ordner src und die Datei pom.xml (und möglicherweise andere Dateien) enthält. Der Inhalt dieses Ordners kann beispielsweise über das Project Tool Window in IntelliJ IDEA angezeigt werden.

Loading
Loading

Im folgenden Beispiel lesen wir alle Zeilen der Datei "file.txt", die dann einer ArrayList hinzugefügt werden.

ArrayList<String> lines = new ArrayList<>();

// wir erstellen einen Scanner zum Lesen der Datei
try (Scanner scanner = new Scanner(Paths.get("file.txt"))) {

    // wir lesen alle Zeilen der Datei
    while (scanner.hasNextLine()) {
        lines.add(scanner.nextLine());
    }
} catch (Exception e) {
    System.out.println("Error: " + e.getMessage());
}

// wir geben die Gesamtzahl der Zeilen aus
System.out.println("Total lines: " + lines.size());
Loading
Loading
Loading

Lesen von Daten in einem bestimmten Format aus einer Datei

Die Welt ist voller Daten, die mit anderen Daten in Beziehung stehen - diese bilden Sammlungen. Beispielsweise können persönliche Informationen einen Namen, ein Geburtsdatum und eine Telefonnummer umfassen. Adressinformationen können hingegen ein Land, eine Stadt, eine Straßenadresse, eine Postleitzahl und so weiter umfassen.

Daten werden häufig in Dateien in einem bestimmten Format gespeichert. Ein solches Format, das uns bereits vertraut ist, ist das CSV-Format (Comma-Separated Values), d.h. durch Kommas getrennte Daten.

Scanner scanner = new Scanner(System.in);

while (true) {
    System.out.print("Enter name and age separated by a comma: ");
    String line = scanner.nextLine();

    if (line.equals("")) {
        break;
    }

    String[] parts = line.split(",");
    String name = parts[0];
    int age = Integer.valueOf(parts[1]);

    System.out.println("Name: " + name);
    System.out.println("Age: " + age);
}

Das Programm funktioniert wie folgt:

Beispielausgabe

Enter name and age separated by a comma: virpi,19 Name: virpi Age: 19 Enter name and age separated by a comma: jenna,21 Name: jenna Age: 21 Enter name and age separated by a comma: ada,20 Name: ada Age: 20

Das Lesen derselben Daten aus einer Datei namens records.txt würde wie folgt aussehen:

try (Scanner scanner = new Scanner(Paths.get("records.txt"))) {

    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();

        String[] parts = line.split(",");
        String name = parts[0];
        int age = Integer.valueOf(parts[1]);

        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}
Loading

Lesen von Objekten aus einer Datei

Das Erstellen von Objekten aus Daten, die aus einer Datei gelesen werden, ist einfach. Angenommen, wir haben eine Klasse namens Person sowie die Daten von zuvor.

Das Lesen von Objekten kann wie folgt durchgeführt werden:

ArrayList<Person> people = new ArrayList<>();

try (Scanner scanner = new Scanner(Paths.get("records.txt"))) {

    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();

        String[] parts = line.split(",");
        String name = parts[0];
        int age = Integer.valueOf(parts[1]);

        people.add(new Person(name, age));
    }
}

System.out.println("Total amount of people read: " + people.size());

Das Lesen von Objekten aus einer Datei ist eine klare Verantwortung an sich und sollte aus diesem Grund in einer Methode isoliert werden. Dies werden wir in der nächsten Übung tun.

Loading
Loading
Sie haben das Ende dieses Abschnitts erreicht! Weiter zum nächsten Abschnitt: