Modernes File Handling in Node.js
Moderne Dateioperationen in Node.js mit fs/promises, Streams, File Handles, Fehlercodes, Parallelität und Schutz vor Path Traversal.
In modernem Node.js ist das promise-basierte Modul node:fs/promises mit async/await die Standardwahl für Datei-I/O. Greifen Sie auf Streams zurück (pipeline aus node:stream/promises), wenn Dateien groß oder von unbekannter Größe sind, und auf File Handles (open/read/close), wenn Sie byteweise positionsgenauen Zugriff benötigen. Das fs-Modul liefert nach wie vor drei parallele APIs — synchron, Callback und Promise — und die meisten älteren Tutorials beginnen mit der Callback-API und CommonJS require(). Diese Herangehensweise ist veraltet: Für neuen Code auf einer aktuellen Laufzeitumgebung ist node:fs/promises mit ES-Modul-import der richtige Ausgangspunkt.
Dieser Artikel zeigt, wie Dateien mit dieser modernen API gelesen, geschrieben und verarbeitet werden: Encoding-Verhalten, Überschreibsemantik, Fehlerbehandlung über code, Nebenläufigkeit mit Promise.all versus Promise.allSettled, die Speichergrenzen, an denen readFile versagt, Streams und File Handles für große Datenmengen, Verzeichnisoperationen sowie die Absicherung gegen Path-Traversal-Angriffe. Die Beispiele richten sich an Node 24, die Active-LTS-Version ab 2026 (Node.js Release-Zeitplan). Alle gezeigten Features liegen deutlich unterhalb dieser Baseline, sodass der Code unverändert auf Node 24 läuft. Sämtliche Beispiele verwenden ESM import mit dem node:-Präfix und Top-Level-await.
Wichtige Erkenntnisse
- Verwenden Sie
node:fs/promisesmitasync/awaitals Standard für Datei-I/O. Synchrone Methoden wiereadFileSyncblockieren den Event Loop und gehören ausschließlich in einmalig ausgeführte CLI-Skripte, niemals in Server. readFilepuffert die gesamte Datei im Arbeitsspeicher und wirftERR_FS_FILE_TOO_LARGEfür jede Datei, die größer als 2 GiB ist — eine feste libuv-I/O-Grenze, unabhängig von den Buffer- und String-Längenbeschränkungen. Ab einigen hundert MiB sollten Sie daher bereits auf Streaming umsteigen.pipeline()ausnode:stream/promises(stabil seit Node 15) verbindet Streams und übernimmt automatisch die Fehlerweiterleitung und das Aufräumen.- Verwenden Sie
Promise.all, wenn jede Datei erfolgreich gelesen werden muss; verwenden SiePromise.allSettled, wenn partielle Fehler akzeptabel sind und Sie das Gelesene weiterverarbeiten möchten. - Übergeben Sie niemals nicht validierte Benutzereingaben an
fs-Funktionen: Lösen Sie den Pfad mitpath.resolveauf und prüfen Sie, ob er innerhalb Ihres vorgesehenen Basisverzeichnisses bleibt, um Path-Traversal-Angriffe zu verhindern.
Die drei fs-APIs und warum fs/promises der Standard ist
Node.js stellt dieselben Dateioperationen über drei APIs bereit: synchron (readFileSync), Callback (readFile(path, cb)) und Promise (node:fs/promises). Die Promise-API wurde in Node 14.0.0 stabil (Node.js 14 Release Notes) und ist der moderne Standard, da sie sich sauber mit async/await integriert und den Event Loop niemals blockiert. Die Callback-API ist Legacy — sie entstand vor Promises und führt zu tief verschachteltem Code — und die synchrone API blockiert den Event Loop für die gesamte Dauer der I/O-Operation. Verwenden Sie die Promise-API für neuen Code.
import { readFile } from 'node:fs/promises'
const data = await readFile('config.json', 'utf8')
console.log(data.length)
Das node:-Präfix kennzeichnet den Import als Node.js-Builtin und kann nicht durch ein npm-Paket gleichen Namens überschattet werden; es identifiziert das Modul explizit als Node.js-Kernmodul. Dieses Beispiel verwendet außerdem Top-Level-await, das seit Node 14.8.0 ohne Flag in ES-Modulen verfügbar ist (Node.js 14.8.0 Release Notes). Sie müssen Dateilesevorgänge auf Modulebene nicht mehr in ein async-IIFE einwickeln.
Welche API sollten Sie verwenden?
Die Entscheidung hängt von der Dateigröße, der Art des benötigten Zugriffs und davon ab, ob der Prozess nebenläufige Arbeit verarbeitet. Verwenden Sie diese Tabelle als Entscheidungsregel:
| Szenario | Empfohlene API | Begründung |
|---|---|---|
| Kleine Dateien, grob unter 100 MB | node:fs/promises readFile/writeFile | Einfachste API; die gesamte Datei passt problemlos in den Arbeitsspeicher, und ein einzelnes await erledigt die Aufgabe |
| Große Dateien oder Dateien unbekannter Größe | Streams: createReadStream/createWriteStream mit pipeline | Konstanter Speicherverbrauch unabhängig von der Größe; die 2-GiB-Grenze von readFile wird vollständig umgangen |
| Byteweiser oder positionsgenaue Zugriff (Lesen/Schreiben an bestimmten Offsets) | File Handles: open/read/close | Nur die Handle-API ermöglicht das Lesen oder Schreiben bestimmter Bytebereiche an gewählten Positionen |
| Einmalige CLI-Skripte und Build-Tools (keine Nebenläufigkeit) | Synchrone Methoden sind akzeptabel: readFileSync/writeFileSync | Das Blockieren des Event Loops ist harmlos, wenn nichts anderes ausgeführt wird |
| HTTP-Server oder jeglicher nebenläufiger Code | Ausschließlich asynchrone Promise-API — niemals synchron | Ein blockierter Event Loop bremst alle ausstehenden Anfragen gleichzeitig aus |
Der Richtwert von ~100 MB ist eine praktische Faustregel dafür, wann auf Streams umgestiegen werden sollte, keine harte Grenze; der tatsächliche Fehlerpunkt für readFile ist die 2-GiB-libuv-Grenze. Wenn Sie zwischen fs/promises und Streams unentschieden sind, ist Streaming die sicherere Standardwahl für alles, dessen Größe Sie nicht kontrollieren.
Dateien lesen mit fs/promises
Discover how at OpenReplay.com.
readFile() lädt die gesamte Datei in den Arbeitsspeicher und gibt entweder einen String oder einen Buffer zurück. Übergeben Sie ein Encoding wie 'utf8', um einen dekodierten String zu erhalten; lassen Sie das Encoding weg, um rohe Bytes als Buffer zu erhalten. Für Konfigurations- und Datendateien lesen Sie als String und parsen:
import { readFile } from 'node:fs/promises'
const raw = await readFile('config.json', 'utf8')
const config = JSON.parse(raw)
console.log(config.port)
Ohne Encoding ist der Rückgabewert ein Buffer — die richtige Wahl für Bilder, Audio oder beliebige Nicht-Text-Daten:
import { readFile } from 'node:fs/promises'
const bytes = await readFile('logo.png') // Buffer
console.log(bytes.length, 'bytes')
JSON.parse wirft bei fehlerhafter Eingabe einen SyntaxError, daher behandelt ein try/catch um den Parse-Vorgang sowohl I/O-Fehler als auch ungültiges JSON. Die vollständige Options-Oberfläche finden Sie in der fs.readFile-Dokumentation.
Dateien schreiben mit fs/promises
writeFile() erstellt die Datei, falls sie nicht existiert, oder überschreibt sie vollständig, falls sie existiert — aus Sicht des Aufrufers ersetzt ein einzelnes await den gesamten Dateiinhalt. Um Inhalte an eine Datei anzuhängen, anstatt sie zu ersetzen, verwenden Sie appendFile(), das die Datei auch dann erstellt, wenn sie fehlt. Um eine Datei auf eine feste Länge zu kürzen, verwenden Sie truncate().
import { writeFile, appendFile } from 'node:fs/promises'
const user = { name: 'Ada', email: 'ada@example.com' }
// Erstellt user.json oder ersetzt den Inhalt vollständig
await writeFile('user.json', JSON.stringify(user, null, 2), 'utf8')
// Fügt eine Zeile hinzu, ohne die Datei neu zu schreiben; erstellt sie, falls nicht vorhanden
await appendFile('events.log', `${new Date().toISOString()} user-created\n`, 'utf8')
truncate(path, n) behält die ersten n Bytes der Datei und verwirft den Rest — das Argument ist die Anzahl der zu behaltenden Bytes, nicht die Anzahl der zu entfernenden Bytes, was dem entgegengesetzt ist, was der Name vermuten lässt. Das Kürzen von 1234567890 auf 5 hinterlässt 12345:
import { writeFile, truncate, readFile } from 'node:fs/promises'
await writeFile('data.txt', '1234567890')
await truncate('data.txt', 5)
console.log(await readFile('data.txt', 'utf8')) // '12345'
Fehlerbehandlung: Abfangen über error.code
Dateioperationen schlagen mit Systemfehlern fehl, die eine code-Eigenschaft tragen; verzweigen Sie über error.code statt Fehlermeldungen zu parsen. Die am häufigsten behandelten Codes sind in der Node.js-Referenz für häufige Systemfehler dokumentiert:
error.code | Bedeutung |
|---|---|
ENOENT | Datei oder Verzeichnis existiert nicht |
EACCES | Zugriff verweigert |
EISDIR | Versucht, ein Verzeichnis als Datei zu lesen |
ENOSPC | Kein Speicherplatz mehr auf dem Gerät (Festplatte voll) |
EMFILE | Zu viele offene File-Deskriptoren |
Ein einzelnes try/catch deckt sowohl den I/O-Fehler als auch bei JSON den Parse-Fehler ab:
import { readFile } from 'node:fs/promises'
try {
const config = JSON.parse(await readFile('config.json', 'utf8'))
console.log('loaded', config)
} catch (error) {
if (error.code === 'ENOENT') {
console.error('config.json fehlt; verwende Standardwerte')
} else if (error.code === 'EACCES') {
console.error('Keine Berechtigung zum Lesen von config.json')
} else {
throw error // Enthält SyntaxError von JSON.parse und unerwartete Codes
}
}
Werfen Sie Codes, die Sie nicht explizit behandeln, erneut, anstatt sie zu schlucken — still abgefangene ENOSPC- oder EMFILE-Fehler sind ein häufiges Produktionsversagen, das die eigentliche Ursache verschleiert.
Sync vs. Async: Wann synchrone Methoden akzeptabel sind
Synchrone fs-Methoden (readFileSync, writeFileSync) blockieren den Node.js-Event-Loop für die gesamte Dauer der I/O-Operation — in der Zwischenzeit wird kein anderes JavaScript ausgeführt. Sie sind in einmalig ausgeführten CLI-Skripten und Build-Tools akzeptabel, wo keine Nebenläufigkeit besteht, aber niemals in HTTP-Servern oder in Code, der nebenläufige Anfragen verarbeitet, da ein blockierter Event Loop alle ausstehenden Anfragen gleichzeitig zum Stillstand bringt (Node.js Event-Loop-Leitfaden).
// Akzeptabel: ein einmaliges Skript, das ausgeführt wird und beendet
import { readFileSync } from 'node:fs'
const pkg = JSON.parse(readFileSync('package.json', 'utf8'))
console.log(pkg.version)
Die Entscheidungsregel: Wenn der Prozess mehr als eine Sache gleichzeitig bedient, verwenden Sie die asynchrone Promise-API.
Nebenläufigkeit: Promise.all vs. Promise.allSettled
Verwenden Sie Promise.all, wenn jeder Dateilesvorgang erfolgreich sein muss und ein einzelner Fehler den gesamten Batch abbrechen soll; verwenden Sie Promise.allSettled, wenn partielle Fehler akzeptabel sind und Sie das Gelesene weiterverarbeiten möchten. Promise.allSettled löst immer auf und gibt ein Array zurück, in dem jeder Eintrag entweder { status: 'fulfilled', value } oder { status: 'rejected', reason } ist.
Das Abbilden von Dateinamen auf Promises ohne await innerhalb der Schleife führt die Lesevorgänge nebenläufig aus:
import { readFile } from 'node:fs/promises'
const files = ['a.json', 'b.json', 'c.json']
// Alles-oder-nichts: eine fehlende Datei lehnt den gesamten Batch ab
const all = await Promise.all(
files.map((f) => readFile(f, 'utf8').then(JSON.parse)),
)
Wenn Sie lieber laden, was vorhanden ist, und den Rest melden möchten, untersuchen Sie die abgeschlossenen Ergebnisse:
import { readFile } from 'node:fs/promises'
const files = ['a.json', 'b.json', 'missing.json']
const results = await Promise.allSettled(
files.map((f) => readFile(f, 'utf8')),
)
const loaded = results.filter((r) => r.status === 'fulfilled').map((r) => r.value)
const failed = results
.filter((r) => r.status === 'rejected')
.map((r) => r.reason.code) // z.B. 'ENOENT'
console.log(`geladen ${loaded.length}, fehlgeschlagen:`, failed)
fs-Promises und große Dateien: Die Speichergrenzen, an denen readFile versagt
readFile puffert die gesamte Datei im Arbeitsspeicher und wirft ERR_FS_FILE_TOO_LARGE für jede Datei, die größer als 2 GiB ist — eine feste libuv-I/O-Grenze, nicht die Buffer-Größengrenze (node#55864, ERR_FS_FILE_TOO_LARGE). Lange vor dieser harten Grenze verursacht das Laden von Hunderten von Megabytes in einen einzelnen Buffer Speicherdruck und langsame Antwortzeiten — ab einigen hundert MiB sollten Sie daher bereits auf Streaming umsteigen.
Drei unterschiedliche Obergrenzen werden leicht verwechselt, und die meisten Tutorials vermischen sie:
| Grenze | Wert (64-Bit) | Gilt für |
|---|---|---|
| libuv-Dateilesegrenze | 2 GiB | readFile für jede Datei; wirft ERR_FS_FILE_TOO_LARGE |
buffer.constants.MAX_STRING_LENGTH | 536.870.888 Bytes (~512 MiB) | Strings, d.h. readFile mit einem Encoding |
buffer.constants.MAX_LENGTH | 2⁵³−1 Bytes (~8 PiB) | Maximale Buffer-Allokation |
Wenn Sie readFile ein Encoding übergeben (was einen String zurückgibt), ist die maßgebliche Obergrenze buffer.constants.MAX_STRING_LENGTH — 536.870.888 Bytes auf 64-Bit-Plattformen, gesenkt von etwa 1 GB in Node 14.4.0 (node#33960). Das Überschreiten dieser Grenze wirft einen „Cannot create a string longer than…”-Fehler, nicht ERR_FS_FILE_TOO_LARGE. Der Wert buffer.constants.MAX_LENGTH ist die maximale Buffer-Allokation und eine wiederum separate Grenze; er begrenzt readFile nicht, das unabhängig davon bei 2 GiB versagt. Die praktische Schlussfolgerung: Leiten Sie das Verhalten von readFile nicht von der Buffer-Grenze ab — die 2-GiB-libuv-Grenze ist diejenige, die zuerst greift.
Streams: createReadStream, createWriteStream und pipeline
Streams verarbeiten Dateidaten in Chunks, anstatt die gesamte Datei im Arbeitsspeicher zu puffern, was sie zum richtigen Werkzeug für große oder größenmäßig unbekannte Dateien macht. createReadStream und createWriteStream erzeugen lesbare und schreibbare Streams; verbinden Sie diese mit pipeline aus node:stream/promises, stabil seit Node 15. pipeline() verbindet einen lesbaren mit einem schreibbaren Stream und übernimmt automatisch die Fehlerweiterleitung und das Aufräumen der Streams. Während pipe() bereits Backpressure verwaltet, bietet pipeline() eine sicherere Fehlerbehandlung und Bereinigung.
import { createReadStream, createWriteStream } from 'node:fs'
import { pipeline } from 'node:stream/promises'
// Kopiert eine Datei beliebiger Größe mit konstantem Speicherverbrauch
await pipeline(
createReadStream('huge-input.log'),
createWriteStream('huge-output.log'),
)
Da pipeline() ein Promise zurückgibt, das bei jedem Stream-Fehler abgelehnt wird und die Streams bei einem Fehler zerstört, genügt ein einzelnes try/catch — es müssen keine 'error'-Listener manuell verdrahtet werden.
Backpressure ist der Mechanismus, der verhindert, dass ein schneller Leser einen langsamen Schreiber überwältigt: Wenn der interne Puffer des Writables voll ist, pausiert der Readable, bis er geleert wird. Der Pufferschwellenwert ist der highWaterMark. Datei-Read-Streams haben standardmäßig einen highWaterMark von 64 KiB, im Gegensatz zu den 16 KiB eines generischen stream.Readable; die fs-Dokumentation nennt den 64-KiB-Wert explizit als Standard für Datei-Streams. Passen Sie ihn an, wenn Profiling zeigt, dass es hilft:
import { createReadStream } from 'node:fs'
const stream = createReadStream('data.bin', { highWaterMark: 128 * 1024 })
Für zeilenbasierte Formate wie CSV leiten Sie den Read-Stream durch einen Parser wie csv-parser, anstatt manuell zu parsen.
File Handles: Byteweiser und positionsgenauer Zugriff
Verwenden Sie ein File Handle von open(), wenn Sie bestimmte Bytebereiche an bestimmten Offsets lesen oder schreiben müssen — etwas, das readFile und Streams nicht ermöglichen. Ein FileHandle ist eine Low-Level-Ressource: Sie verwalten Buffer und Position selbst und müssen das Handle immer mit close() in einem finally-Block freigeben, sonst entsteht ein Deskriptor-Leak (und genug Leaks erzeugen EMFILE).
import { open } from 'node:fs/promises'
async function readInChunks(path) {
let handle
try {
handle = await open(path, 'r')
const chunkSize = 64 * 1024
const buffer = Buffer.alloc(chunkSize)
let position = 0
while (true) {
const { bytesRead } = await handle.read(buffer, 0, chunkSize, position)
if (bytesRead === 0) break
// buffer.subarray(0, bytesRead) verarbeiten
position += bytesRead
}
} finally {
await handle?.close()
}
}
handle.read(buffer, offset, length, position) füllt buffer ab einer gegebenen Datei-position und meldet bytesRead; das manuelle Nachverfolgen von position ermöglicht den positionsgenauen Zugriff. Für die meisten Kopier- und Transformationsaufgaben sind Streams das bessere Werkzeug — File Handles sind die Ausführlichkeit nur dann wert, wenn Sie wirklich byteweisen Zugriff benötigen.
AbortSignal wird von readFile und fs.watch unterstützt, sodass ein langsamer Lesevorgang abgebrochen werden kann — beispielsweise wenn eine Anfrage das Timeout überschreitet. Ein abgebrochener Lesevorgang wird mit einem Fehler abgelehnt, dessen name 'AbortError' ist:
import { readFile } from 'node:fs/promises'
const controller = new AbortController()
setTimeout(() => controller.abort(), 1000)
try {
await readFile('slow-source.bin', { signal: controller.signal })
} catch (error) {
if (error.name === 'AbortError') console.error('Lesevorgang abgebrochen')
else throw error
}
Verzeichnisse und Pfade
Erstellen Sie verschachtelte Verzeichnisse mit mkdir({ recursive: true }) (kein Fehler, wenn sie bereits existieren, ähnlich wie mkdir -p), listen Sie Einträge mit readdir({ withFileTypes: true }) auf, um Dirent-Objekte zu erhalten, und entfernen Sie einen Verzeichnisbaum mit rm({ recursive: true }) — alles aus demselben node:fs/promises-Modul. Erstellen Sie Pfade mit path.join, damit Trennzeichen betriebssystemübergreifend korrekt sind.
import { mkdir, readdir, rm } from 'node:fs/promises'
import { join } from 'node:path'
await mkdir('output/reports', { recursive: true })
const entries = await readdir('output', { withFileTypes: true })
for (const entry of entries) {
const full = join('output', entry.name)
if (entry.isFile()) console.log('Datei:', full)
else if (entry.isDirectory()) console.log('Verz.:', full)
}
await rm('output/reports', { recursive: true, force: true })
Iterieren Sie das Array mit for...of, nicht mit for...in — for...in über ein Array liefert String-Indizes, keine Werte, ein häufiger Fehler in älteren Anleitungen. rm (mit recursive: true) ist der aktuelle Weg zum Löschen von Verzeichnisbäumen; rmdir mit der rekursiven Option ist veraltet.
Um Dateien relativ zum aktuellen Modul statt zum Arbeitsverzeichnis des Prozesses zu referenzieren, verwenden Sie import.meta.dirname. Verfügbar seit Node 20.11.0 (import.meta.dirname), bietet es ES-Modulen dieselbe Verzeichnisreferenz, die __dirname in CommonJS bereitstellte:
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
const config = await readFile(join(import.meta.dirname, 'config.json'), 'utf8')
Berechtigungs- und Eigentümerfunktionen (chmod, chown) sowie Link-Funktionen (symlink, link) sind ebenfalls in der Promise-API vorhanden, gelten jedoch für Unix-ähnliche Systeme und verhalten sich unter Windows unerwartet oder werfen Fehler; behandeln Sie sie als plattformspezifisch.
Sicherheit: Path-Traversal mit Benutzereingaben verhindern
Übergeben Sie niemals vom Benutzer stammende Strings direkt an readFile, writeFile oder eine andere fs-Funktion. Normalisieren Sie den Pfad mit path.resolve und prüfen Sie, ob er mit Ihrem vorgesehenen Basisverzeichnis beginnt, bevor Sie fortfahren — eine rohe Eingabe wie ../../../etc/passwd traversiert andernfalls aus jedem relativen Pfad heraus, den Sie einschränken wollten. Ein naives join(baseDir, userInput) schützt Sie nicht, da ..-Segmente nach oben aufgelöst werden.
import { resolve, sep } from 'node:path'
import { readFile } from 'node:fs/promises'
const baseDir = resolve('uploads')
async function readUserFile(userPath) {
const target = resolve(baseDir, userPath)
if (target !== baseDir && !target.startsWith(baseDir + sep)) {
throw new Error('Path-Traversal blockiert')
}
return readFile(target, 'utf8')
}
Durch das vorherige Auflösen und anschließende Prüfen des Präfixes gegen baseDir + sep wird die Anfrage unabhängig davon, wie viele ..-Segmente die Eingabe enthält, innerhalb des erlaubten Verzeichnisses gehalten. Der + sep-Schutz verhindert, dass ein Geschwisterverzeichnis wie uploads-private eine bloße startsWith('uploads')-Prüfung besteht.
Fazit
Beginnen Sie für neuen Node.js-Code mit node:fs/promises und async/await, steigen Sie auf Streams mit pipeline() um, sobald Dateien einige hundert Megabytes überschreiten oder eine unbekannte Größe haben, und wechseln Sie nur dann zu File Handles, wenn Sie byteweisen positionsgenauen Zugriff benötigen. Ordnen Sie jede Operation ihrer tatsächlichen Einschränkung zu — Speicherobergrenze, Nebenläufigkeit und nicht vertrauenswürdige Eingaben sind die drei, die am häufigsten zu Problemen führen — und greifen Sie auf die offizielle fs-Dokumentation zurück, wenn Sie die vollständige Options-Oberfläche benötigen. Der nächste Schritt besteht darin, vorhandenen Callback- oder Sync-fs-Code in Ihren Servern zu prüfen und auf die Promise-API zu migrieren.
FAQs
Was ist der Unterschied zwischen fs und fs/promises in Node.js?
Beide beziehen sich auf dieselben Dateioperationen, stellen jedoch unterschiedliche Schnittstellen bereit. Das Basismodul node:fs bietet synchrone Methoden (readFileSync) und Callback-basierte asynchrone Methoden (readFile mit einem Callback-Argument), während node:fs/promises Promise-zurückgebende Versionen derselben Operationen bereitstellt, die mit async und await funktionieren. Die Promise-API wurde in Node 14.0.0 stabil und ist der empfohlene Standard für neuen Code, da sie Callback-Verschachtelung vermeidet und den Event Loop niemals blockiert.
Kann ich require mit fs/promises verwenden, oder benötige ich ES-Module?
Sie können beides verwenden. In ES-Modulen schreiben Sie import { readFile } from 'node:fs/promises'. In CommonJS schreiben Sie const { readFile } = require('node:fs/promises'). Die Promise-API selbst erfordert kein ESM; nur Top-Level-await und import.meta.dirname benötigen einen ES-Modul-Kontext. Das node:-Präfix funktioniert in beiden Formaten und kennzeichnet den Import als Node.js-Builtin, das kein npm-Paket überschatten kann.
Warum wirft readFile ERR_FS_FILE_TOO_LARGE, bevor die Buffer-Größengrenze erreicht wird?
ERR_FS_FILE_TOO_LARGE ist eine feste 2-GiB-libuv-I/O-Grenze für eine einzelne Leseoperation, unabhängig von der Buffer-Allokationsgrenze. Eine Datei knapp über 2 GiB schlägt fehl, obwohl buffer.constants.MAX_LENGTH weit höher ist, da der zugrundeliegende Lese-Syscall-Pfad die 2-GiB-Grenze unabhängig davon durchsetzt, wie viel Speicher ein Buffer halten könnte. Um größere Dateien zu verarbeiten, verwenden Sie Streams mit pipeline anstatt die gesamte Datei zu puffern.
Wie lese ich einen Teil einer Datei an einem bestimmten Byte-Offset?
Öffnen Sie die Datei mit open() aus node:fs/promises, um ein FileHandle zu erhalten, und rufen Sie dann handle.read(buffer, offset, length, position) auf, das buffer ab der angegebenen Dateiposition füllt und bytesRead meldet. Verfolgen Sie position manuell über mehrere Lesevorgänge hinweg, um durch die Datei zu navigieren. Geben Sie das Handle immer mit handle.close() in einem finally-Block frei, sonst entsteht ein Deskriptor-Leak, und genug Leaks erzeugen EMFILE. Einfaches readFile und Streams ermöglichen keinen positionsgenauen Zugriff.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k