mitmario.dev

Wenn der Zugriff scheitert

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

Dateizugriffe scheitern. Nicht selten, sondern ständig, und meistens aus Gründen, die mit deinem Code nichts zu tun haben. Die Datei ist noch nicht da. Jemand hat sie umbenannt. Die Platte ist voll. Ein Backup-Prozess hält sie gerade fest.

Ein Programm, das dabei umfällt, ist kein Programm, sondern ein Prototyp. Deshalb hat dieses Thema eine eigene Lektion.

Fehler haben einen Code

try und catch kennst du aus dem JavaScript-Kurs. Neu ist, was im Fehlerobjekt steht.

Ein Fehler mit Code
import { readFile } from "node:fs/promises";

try {
  await readFile("gibtesnicht.txt", "utf8");
} catch (fehler) {
  console.log("Code:", fehler.code);
  console.log("Meldung:", fehler.message);
  console.log("Pfad:", fehler.path);
}

Drei Felder sind interessant. code ist eine kurze Kennung, message ein Satz für Menschen, und path sagt, um welche Datei es ging.

Prüf immer auf code, nie auf message. Der Text ist Beiwerk und kann sich mit einer neuen Node-Version ändern, außerdem hängt er teilweise am Betriebssystem. Der Code ist eine Zusage. Wer fehler.message.includes("no such file") schreibt, baut eine Bedingung, die irgendwann still nicht mehr zutrifft.

Die drei, die du kennen musst

ENOENT heißt: An diesem Pfad ist nichts. Der häufigste von allen. Er kommt beim Lesen, beim Schreiben in einen fehlenden Ordner und beim Umbenennen.

EACCES heißt: Die Datei ist da, aber du darfst nicht. Auf dem eigenen Rechner siehst du ihn selten, auf einem Server ständig, weil dort ein Dienstbenutzer läuft und nicht du.

EISDIR heißt: Das ist ein Ordner, keine Datei.

Ein Ordner ist keine Datei
import { readFile } from "node:fs/promises";

// daten ist ein Ordner, keine Datei.
try {
  await readFile("daten", "utf8");
} catch (fehler) {
  console.log("Code:", fehler.code);
  console.log("Meldung:", fehler.message);
}

Es gibt noch ein paar weitere, und du wirst sie im Lauf der Zeit kennenlernen. EEXIST beim Anlegen von etwas, das es schon gibt. ENOTEMPTY beim Löschen eines Ordners, in dem noch etwas liegt. ENOSPC, wenn die Platte voll ist. Alle nach demselben Muster: ein E, dann eine Abkürzung.

Die Unterscheidung, auf die es ankommt

Jetzt der Teil, der über die Qualität deines Programms entscheidet, und er hat mit Node wenig zu tun.

Manche Fehler kannst du erwarten. Die Konfigurationsdatei fehlt beim allerersten Start. Das ist kein Unglück, sondern der Normalfall, und die richtige Reaktion sind Standardwerte.

Manche Fehler kannst du nicht erwarten. Die Rechte stimmen nicht, die Platte ist voll, der Pfad zeigt auf einen Ordner. Da ist etwas grundsätzlich anders, als du angenommen hast, und die richtige Reaktion ist: sagen, was los ist, und aufhören.

Erwartet und unerwartet auseinanderhalten
import { readFile } from "node:fs/promises";

try {
  const roh = await readFile("einstellungen.json", "utf8");
  console.log("Geladen:", roh.length, "Zeichen");
} catch (fehler) {
  if (fehler.code === "ENOENT") {
    console.log("Noch keine Einstellungen, ich lege später welche an");
  } else {
    console.error("Damit habe ich nicht gerechnet:", fehler.code);
    process.exit(1);
  }
}

console.log("Weiter geht es");

Genau diese Form wirst du gleich selbst schreiben. Der erwartete Fall bekommt seinen eigenen Zweig, alles andere fällt in den else.

Was du dabei nicht tun solltest: einen catch-Block schreiben, der jeden Fehler schluckt und einfach weitermacht. Das sieht robust aus und ist das Gegenteil. Dein Programm läuft dann mit falschen Annahmen weiter, und der eigentliche Fehler taucht drei Schritte später an einer Stelle auf, die damit nichts zu tun hat.

Faustregel: Fang genau die Fehler ab, für die du eine Antwort hast. Für alle anderen ist Abbruch die ehrlichste Reaktion. In Abschnitt 16 bekommt diese Unterscheidung einen Namen und einen festen Platz in der Anwendung.

Warum man nicht vorher fragt

In der vorigen Lektion stand schon, dass man in Node nicht erst prüft, ob eine Datei existiert. Jetzt siehst du die Alternative in ganzer Länge, und sie ist nicht länger.

Der try-Block macht genau einen Versuch. Klappt er, ist alles gut. Klappt er nicht, weißt du dank code sogar genauer, warum, als eine Vorab-Prüfung dir je hätte sagen können.

Zum Mitnehmen

Prüf auf err.code, nicht auf err.message. Der Text kann sich mit der nächsten Node-Version ändern, der Code nicht.

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.