Node.js I/O

Node.js File System

Das fs-Modul liest, schreibt und überwacht Dateien. Nutzen Sie die Promise-API, behandeln Sie Pfade sicher und verwenden Sie Streams für große Datenmengen.

intermediate14 min readUpdated 15. Sept. 2026
config.js
js
// config.js
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";

const file = path.join(import.meta.dirname, "config.json");

const config = JSON.parse(await readFile(file, "utf8"));
config.updatedAt = new Date().toISOString();

await writeFile(file, JSON.stringify(config, null, 2));
Modul
node:fs/promises
Pfade
node:path
Kodierung
utf8 für Text
Verzeichnisse
mkdir, readdir, rm
Große Dateien
Streams
Sicherheit
Schutz vor Path Traversal

Warum es wichtig ist

Warum Dateiverarbeitung wichtig ist

Permanenter Speicher

Dateien speichern Konfigurationen, Uploads, Logs und generierte Ausgaben, die einen Neustart überstehen müssen.

Sicherheit ist entscheidend

Nicht vertrauenswürdige Pfade und unbegrenzte Leseoperationen gehören zu den häufigsten serverseitigen Schwachstellen.

Streaming hält den Speicherverbrauch niedrig

Streamen Sie große Dateien, anstatt sie zu puffern, damit der Speicherbedarf nicht mit der Dateigröße wächst.

Das Gesamtbild

Die drei Säulen der Dateiarbeit

Inhalte lesen und schreiben, Pfade und Verzeichnisse sicher verwalten und alles, was groß sein könnte, streamen.

Inhalt

Lesen und Schreiben

Dateien lesen, schreiben und ergänzen, inklusive Kodierung für Text.

Pfade

Lokalisieren

Das path-Modul verbindet, löst und normalisiert Pfade plattformübergreifend.

Streaming

Skalierung

Nutzen Sie Streams für große Dateien und Pipelines für die Verarbeitung.

Das Dateisystem auf einen Blick

Die Kern-APIs

readFile und writeFile

Ganze Dateien als String oder Buffer lesen und schreiben.

mkdir und readdir

Verzeichnisse erstellen und auflisten.

path Modul

join, resolve, basename, extname und normalize.

stat

Existenz, Größe, Typ und Zeitstempel prüfen.

watch

Auf Dateiänderungen reagieren für Dev-Server und Tooling.

Streams

createReadStream und createWriteStream für große Datenmengen.

Eine kurze Geschichte

Von Callback-fs zu Promise-basiertem I/O

  1. 2009

    Callback fs

    Node ermöglicht Dateizugriff über Error-First-Callbacks.

    09
  2. 2014

    fs.promises vorgeschlagen

    Eine Promise-basierte API wird für modernes JavaScript entworfen.

    14
  3. 2019

    fs/promises stabil

    Promise-Methoden werden zur empfohlenen Art der Nutzung von fs.

    19
  4. 2023

    Glob-Unterstützung

    Integrierte Glob-Patterns ersetzen eine häufige externe Abhängigkeit.

    23
  5. Heute

    Promises zuerst

    Asynchroner Dateizugriff ist Standard; Sync-APIs sind für Skripte und den Startup-Prozess gedacht.

    Heute

Der vollständige Leitfaden

Node.js File System: Alles was Sie wissen müssen

Warum die Dateiverarbeitung wichtig ist

Server lesen und schreiben ständig Dateien: Konfigurationen, Uploads, Logs, Caches, generierte Berichte und Build-Outputs. Das node:fs-Modul von Node.js ist die entsprechende Schnittstelle, und die Art und Weise, wie Sie es einsetzen, entscheidet darüber, ob Ihr Server reaktionsfähig bleibt und Ihre Daten sicher sind.

Drei Dinge sind dabei besonders wichtig: Nutzen Sie die Promise API, damit der Event Loop nicht blockiert wird. Erstellen Sie Pfade sicher, damit Benutzereingaben nicht aus einem Verzeichnis ausbrechen können. Und verwenden Sie Streams für große Dateien, damit der Speicherverbrauch nicht mit der Dateigröße ansteigt.

Dateien lesen und schreiben

Die Promise-API ist der Standard für den Anwendungscode.

// files.js
import { readFile, writeFile, appendFile } from "node:fs/promises";

// text
const text = await readFile("notes.md", "utf8");
await writeFile("notes.md", text + "\nnew line\n", "utf8");
await appendFile("app.log", "event\n", "utf8");

// binary
const image = await readFile("photo.png"); // Buffer
await writeFile("copy.png", image);

Übergeben Sie eine Kodierung wie "utf8", um einen String zu erhalten; lassen Sie diese weg, um ein Buffer mit rohen Bytes zu erhalten. writeFile ersetzt die Datei, während appendFile Inhalte hinzufügt. Keine der beiden Methoden erstellt fehlende Verzeichnisse, rufen Sie daher bei Bedarf zuerst mkdir auf.

Verzeichnisse

// dirs.js
import { mkdir, readdir, rm, rename, stat } from "node:fs/promises";

await mkdir("data/cache", { recursive: true });

const entries = await readdir("data", { withFileTypes: true });
for (const entry of entries) {
  if (entry.isDirectory()) console.log("dir", entry.name);
}

const info = await stat("data/cache");
console.log(info.size, info.mtime);

await rename("data/tmp.json", "data/final.json");
await rm("data/old", { recursive: true, force: true });

recursive: true sorgt dafür, dass mkdir und rm auf gesamten Verzeichnisbäumen operieren, und withFileTypes gibt Einträge zurück, die ohne zusätzliche stat-Aufrufe geprüft werden können. Verwenden Sie stat, um die Existenz, Größe und Zeitstempel zu prüfen, aber beachten Sie, dass es Symlinks folgt; lstat tut dies nicht.

Pfade

Das node:path Modul ermöglicht die portable Manipulation von Pfaden.

// paths.js
import path from "node:path";

const file = path.join("uploads", "avatars", "ada.png");
const absolute = path.resolve("uploads", "ada.png");
const name = path.basename(file);          // ada.png
const ext = path.extname(file);            // .png
const dir = path.dirname(file);            // uploads/avatars

Verwenden Sie path.join und path.resolve anstelle von String-Konkatenation sowie import.meta.dirname (oder import.meta.url in älteren Versionen), um Dateien relativ zum aktuellen Modul zu lokalisieren. Unter Windows verwendet path Backslashes, weshalb eine manuelle Konkatenation zu Fehlern führt.

Sicherheit: Path Traversal

Die häufigste Dateivulnerabilität besteht darin, dass Benutzereingaben das beabsichtigte Verzeichnis verlassen können.

// safe-path.js
import path from "node:path";

const BASE = "/srv/uploads";

function safePath(name) {
  const target = path.resolve(BASE, name);
  if (target !== BASE && !target.startsWith(BASE + path.sep)) {
    throw new Error("Invalid path");
  }
  return target;
}

Lösen Sie die Eingabe gegen eine feste Basis auf und überprüfen Sie anschließend, ob das Ergebnis immer noch innerhalb dieser Basis liegt. Validieren Sie zudem Dateinamen, lehnen Sie Null-Bytes ab und geben Sie niemals rohe Dateisystemfehler an Clients weiter. Weitere Informationen finden Sie im Web Security Guide.

Atomare Schreibvorgänge

Wenn es während eines Schreibvorgangs zu einem Absturz kommt, kann ein Reader eine halb geschriebene Datei sehen. Schreiben Sie Zustände und Konfigurationen stattdessen in eine temporäre Datei und benennen Sie diese anschließend an die Zielposition um.

// atomic.js
import { writeFile, rename } from "node:fs/promises";
import { randomUUID } from "node:crypto";

const tmp = `/srv/state/.${randomUUID()}.tmp`;
await writeFile(tmp, JSON.stringify(state), "utf8");
await rename(tmp, "/srv/state/current.json");

rename ist auf demselben Dateisystem atomar, sodass Reader immer entweder die alte Datei oder die vollständig neue Datei sehen.

Große Dateien streamen

Verwenden Sie bei allem, was groß werden könnte, Streams anstelle von Buffering.

// stream.js
import { createReadStream, createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";

await pipeline(
  createReadStream("big.csv"),
  createWriteStream("copy.csv"),
);

Streaming hält den Speicherverbrauch konstant und ermöglicht es Ihnen, mit der Verarbeitung zu beginnen, noch bevor die gesamte Datei eingelesen wurde. Der Streams guide behandelt Transforms, Backpressure und den Object Mode.

Dateien überwachen

// watch.js
import { watch } from "node:fs";

const watcher = watch("./config", { recursive: true }, (event, filename) => {
  console.log(event, filename);
});

process.on("SIGINT", () => watcher.close());

Watcher eignen sich ideal für Dev-Server und das Neuladen von Konfigurationen. Nutze Debouncing für Event-Bursts, behandle Löschvorgänge sowie Umbenennungen und schließe den Watcher immer ab, damit der Prozess beendet werden kann.

Best Practices

  • Verwenden Sie node:fs/promises im Anwendungscode.
  • Lesen und schreiben Sie mit einer expliziten Kodierung oder erwarten Sie einen Buffer.
  • Erstellen Sie Pfade mit node:path und lösen Sie diese relativ zu einer bekannten Basis auf.
  • Schützen Sie sich vor Path Traversal bei jedem vom Benutzer bereitgestellten Dateinamen.
  • Streamen Sie große Dateien; puffern Sie nur das, was Sie als Ganzes benötigen.
  • Schreiben Sie Zustandsdateien atomar mithilfe einer temporären Datei und einem anschließenden Umbenennen.
  • Schließen Sie Watcher und File Handles, damit Prozesse sauber beendet werden können.

Häufige Fehler

  • Verwendung von readFileSync in einem Request-Handler.
  • Konkatenierung von Benutzereingaben in Pfaden.
  • Die Annahme, dass ein Verzeichnis existiert, bevor geschrieben wird.
  • Einlesen riesiger Dateien in den Arbeitsspeicher, was unter Last zu Abstürzen führt.
  • Ausgeben von rohen Dateisystemfehlern und das damit verbundene Leaken von Pfaden.
  • Vergessen, Watcher oder Streams zu schließen.

Wie geht es weiter?

Die Dateiverarbeitung gehört zu den täglichen Aufgaben auf dem Server. Vertiefe dein Wissen mit Streams, verstehe das Scheduling im Event Loop Guide und sichere deine Pfade mit dem Web Security Guide ab.

Eine Datei lesen

Nutzen Sie in Servern die Promise-API, damit der Event Loop frei bleibt. Sync-Aufrufe blockieren jede andere Anfrage.

Bevorzugt
import { readFile } from "node:fs/promises";

const text = await readFile("data.json", "utf8");
Vermeiden
import { readFileSync } from "node:fs";

// blocks the whole server
const text = readFileSync("data.json", "utf8");

Einen Pfad erstellen

Lösen Sie Benutzereingaben gegen eine feste Basis auf und lehnen Sie alles ab, was diese verlässt. String-Konkatenation lädt zu Path Traversal ein.

Bevorzugt
import path from "node:path";

const base = "/srv/uploads";
const target = path.resolve(base, name);

if (!target.startsWith(base + path.sep)) {
  throw new Error("Invalid path");
}
Vermeiden
// "../../etc/passwd" escapes
// the intended directory
const target = "/srv/uploads/" + name;

Häufig gestellte Fragen

Häufig gestellte Fragen

Keep learning

Related topics from the roadmap.

$ Lernen Sie jetzt

Bereit, File System zu lernen?

Unser interaktives Tutorial führt Sie Schritt für Schritt durch File System — mit Quizzen und echtem Code, den Sie im Browser ausführen können.