mitmario.dev

Verzeichnisse

Node.js Sandbox 3 Min Lesezeit 3 BeispieleLektion 3 von 7

Eine einzelne Datei zu lesen ist der einfache Fall. Meistens weißt du aber gar nicht, welche Dateien es gibt, sondern willst genau das erst herausfinden.

Einen Ordner auflesen

readdir gibt dir die Namen der Einträge in einem Verzeichnis.

Einen Ordner auflesen
import { readdir } from "node:fs/promises";

// readdir garantiert keine Reihenfolge, deshalb wird hier sortiert.
const namen = (await readdir("inhalt")).sort();

console.log(namen);
console.log("Anzahl:", namen.length);

Zwei Dinge fallen daran auf.

Es sind Namen, keine Pfade. In der Liste steht aufgaben.txt und nicht inhalt/aufgaben.txt. Der Ordner, den du gerade abgefragt hast, taucht in den Ergebnissen nicht auf.

Die Reihenfolge ist nicht garantiert. Node reicht durch, was das Betriebssystem liefert, und das ist je nach Dateisystem die Reihenfolge des Anlegens, eine Hash-Reihenfolge oder etwas ganz anderes. Auf deinem Rechner sieht es oft sortiert aus, auf dem Server nicht. Wenn du eine Reihenfolge brauchst, sortier selbst. Das ist eine Zeile und erspart dir einen Fehler, der nur woanders auftritt.

Die Falle mit dem Namen

Jetzt der Fehler, den in Node fast jeder einmal macht.

Ein Name ist noch kein Pfad
import { readdir, readFile } from "node:fs/promises";

const namen = (await readdir("inhalt")).sort();

console.log("Gefunden:", namen[1]);

// Gesucht wird im Arbeitsverzeichnis, nicht in inhalt/.
await readFile(namen[1], "utf8");

Der Name aus readdir ist relativ zu dem Ordner, den du aufgelesen hast. readFile löst ihn aber gegen das Arbeitsverzeichnis auf, und dort liegt die Datei nicht. Ergebnis: ENOENT für eine Datei, die du gerade selbst in der Liste gesehen hast. Im Terminal steht erst Gefunden: notizen.txt und darunter in Rot ENOENT: no such file or directory, open 'notizen.txt', und der Pfad in der Meldung sagt es schon: kein inhalt/ davor.

Das kannst du dir im Terminal ansehen, statt es zu glauben. ls zeigt, was im Arbeitsverzeichnis liegt, nämlich index.mjs und den Ordner inhalt. ls inhalt zeigt, was darin liegt, nämlich die beiden Textdateien. readFile sucht in der ersten Liste, gefunden hast du den Namen in der zweiten.

Die Lösung kennst du schon aus Lektion 2.4: path.join("inhalt", name). Genau dafür gibt es node:path, und genau hier merkst du zum ersten Mal, warum.

Datei oder Ordner

readdir allein sagt dir nicht, was hinter einem Namen steckt. Dafür gibt es zwei Wege.

Der bequeme ist withFileTypes: true. Dann bekommst du statt Zeichenketten kleine Objekte, die ihren Namen kennen und die Frage isDirectory() beantworten können.

Datei oder Ordner
import { readdir } from "node:fs/promises";

const eintraege = await readdir("inhalt", { withFileTypes: true });
eintraege.sort((a, b) => a.name.localeCompare(b.name));

for (const eintrag of eintraege) {
  console.log(`${eintrag.name} (${eintrag.isDirectory() ? "Ordner" : "Datei"})`);
}

In inhalt liegt neben der Textdatei ein Ordner archiv, und genau den unterscheidet das Beispiel: archiv (Ordner) über aufgaben.txt (Datei).

Der allgemeine Weg ist stat(pfad). Es liefert deutlich mehr: Größe in Bytes, Zeitpunkt der letzten Änderung, Rechte, und ebenfalls isDirectory() und isFile(). Dafür brauchst du einen richtigen Pfad und einen Aufruf je Eintrag.

Faustregel: Willst du nur wissen, ob Datei oder Ordner, nimm withFileTypes. Willst du Größe oder Datum, nimm stat.

Ordner anlegen

mkdir("berichte") legt einen Ordner an und scheitert, wenn es ihn schon gibt oder wenn der übergeordnete Ordner fehlt.

Deshalb schreibt man in der Praxis fast immer mkdir("berichte/2026", { recursive: true }). Das legt den ganzen Weg an, und, das ist der eigentliche Gewinn, es beschwert sich nicht, wenn schon alles da ist. Damit kannst du es bei jedem Start aufrufen, ohne vorher zu prüfen.

Warum man vorher nicht prüft

Damit sind wir bei einer Gewohnheit, die in Node anders ist als anderswo. Es gibt zwar eine Funktion, die fragt, ob etwas existiert, aber man benutzt sie besser nicht.

Der Grund: Zwischen deiner Frage und deiner Handlung liegt ein Moment, und in diesem Moment kann sich die Welt ändern. Ein anderer Prozess löscht die Datei, ein Backup verschiebt sie, ein Benutzer räumt auf. Dein Code hat dann geprüft, dass alles in Ordnung ist, und stürzt eine Zeile später trotzdem ab.

Die Node-Denkweise ist deshalb: versuch es einfach und fang den Fehler ab. Das ist nicht nur sicherer, sondern auch kürzer. Wie das aussieht, kommt in der nächsten Lektion.

Zum Mitnehmen

readdir gibt dir Namen, keine Pfade. Wer einen Namen direkt an readFile weiterreicht, sucht im falschen Verzeichnis.

Jetzt du

Basis Konto, kostenlos

Zu 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.