Abschnitt 3 · Lektion 1
Dateien lesen
Ab hier kann Node etwas, was der Browser nie können wird: an die Festplatte. Und ab hier bleibt zum ersten Mal etwas übrig, wenn dein Programm fertig ist.
Zwei Arten, dasselbe Modul zu benutzen
node:fs gibt es in zwei Ausführungen. Die ältere arbeitet mit Rückruffunktionen, die neuere mit
Promises und heißt node:fs/promises. Es ist dasselbe Modul und dieselbe Funktionalität, nur die
Schreibweise unterscheidet sich.
Wir nehmen in diesem Kurs durchgehend node:fs/promises, weil du await schon kennst und weil
verschachtelte Rückruffunktionen ab drei Dateien unlesbar werden. In altem Code wirst du die
Callback-Variante trotzdem sehen.
Daneben gibt es in node:fs zu jeder Funktion noch eine Variante mit Sync am Ende, also
readFileSync statt readFile. Die wartet, bis die Datei da ist, und blockiert dabei alles andere.
Warum das ein Problem ist, klärt Abschnitt 6.
Kaffee
Tee
Kakao import { readFile } from "node:fs/promises";
const text = await readFile("liste.txt", "utf8");
console.log(text);
console.log("Zeichen:", text.length);
console.log("Zeilen:", text.trim().split("\n").length); Mehr ist es nicht: Dateiname rein, Inhalt raus. Der Pfad wird relativ zum Arbeitsverzeichnis aufgelöst, nicht relativ zu deiner Datei. Das ist genau der Unterschied aus Lektion 2.4, und er trifft dich hier zum ersten Mal wirklich.
Der zweite Parameter, den man einmal vergisst
"utf8" sagt Node, wie es die Bytes in der Datei als Text deuten soll. Lässt du es weg, deutet Node
gar nichts und gibt dir die Bytes selbst.
Kaffee
Tee
Kakao import { readFile } from "node:fs/promises";
// Der zweite Parameter fehlt, deshalb kommen rohe Bytes zurück.
const roh = await readFile("liste.txt");
console.log("Roh:", roh);
console.log("Typ:", roh.constructor.name);
console.log("Als Text:", roh.toString("utf8").trim()); Ein Buffer ist eine Liste von Bytes, ausgegeben in Hexadezimalschreibweise. Du kannst darin sogar
etwas erkennen: 4b ist das K von Kaffee, und 0a ist der Zeilenumbruch.
Verwirrend wird es dadurch, dass ein Buffer sich in vielen Situationen wie Text benimmt. Hängst du
ihn an eine Zeichenkette, wandelt JavaScript ihn stillschweigend um. Rufst du .trim() darauf auf,
gibt es einen Fehler, denn ein Buffer hat diese Methode nicht. Der Fehler kommt dann an einer ganz
anderen Stelle als die vergessene Angabe.
Buffer sind kein Unfall, sondern der richtige Datentyp für alles, was kein Text ist: Bilder, PDFs,
Videos. Abschnitt 7 nimmt sie sich richtig vor. Für Textdateien schreibst du "utf8" dazu, und zwar
jedes Mal.
Was du mit dem Text danach machst
Eine Textdatei kommt als eine einzige lange Zeichenkette zurück, mit Zeilenumbrüchen darin. Der übliche erste Schritt ist deshalb Zerlegen.
Kaffee;20
Tee;10
Kakao;5 import { readFile } from "node:fs/promises";
const text = await readFile("preise.txt", "utf8");
const zeilen = text.trim().split("\n");
for (const zeile of zeilen) {
const [name, preis] = zeile.split(";");
console.log(`${name}: ${Number(preis).toFixed(2)} EUR`);
} Beachte das trim() vor dem split(). Fast jede Textdatei endet mit einem Zeilenumbruch, und ohne
trim() hättest du am Ende eine leere Zeile mit, die du beim Zählen nicht erwartest. Das ist eine
der Kleinigkeiten, die einen Nachmittag kosten können.
Und wenn die Datei groß ist?
readFile holt die ganze Datei in den Arbeitsspeicher, bevor du die erste Zeile siehst. Bei
einer Liste mit dreißig Einträgen ist das völlig egal.
Bei einer Logdatei mit zwei Gigabyte ist es das nicht. Dein Programm braucht dann zwei Gigabyte Speicher, und wenn es die nicht bekommt, stürzt es ab, ohne eine einzige Zeile verarbeitet zu haben.
Für diesen Fall gibt es Streams, also einen Weg, eine Datei stückweise durchlaufen zu lassen, ohne
sie je vollständig zu halten. Abschnitt 7 baut das auf. Bis dahin gilt: readFile ist für Dateien,
deren Größe du kennst und die in den Speicher passen.
Zum Mitnehmen
Ohne den zweiten Parameter bekommst du keinen Text zurück, sondern rohe Bytes. Beim Ausgeben sieht man den Unterschied sofort.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe, dein Code läuft auf einem Server
Öffnet sich mit dem Basis Konto.