Start · Sprachen · JavaScript · Referenz · FileSystemFileHandle.createWritable()

FileSystemFileHandle.createWritable()

Methode

Erstellt einen <code>FileSystemWritableFileStream</code>, über den Daten in die vom Handle referenzierte Datei geschrieben werden.

seit JavaScript Chromium 86+ (Chrome, Edge, Opera); Safari 26+/OPF Kategorie: webapi

Signatur

FileSystemFileHandle.prototype.createWritable(options)

Beschreibung

Die Methode createWritable() eines FileSystemFileHandle liefert ein Promise, das zu einem FileSystemWritableFileStream aufgelöst wird. Dieser Stream ist ein WritableStream mit Zusatzmethoden wie write(), seek() und truncate(). So lassen sich lokale Dateien bearbeiten, etwa aus einem Handle von showSaveFilePicker() oder showOpenFilePicker(), oder Dateien im Origin Private File System (OPFS).

Geschrieben wird zunächst in eine temporäre Datei. Erst beim Aufruf von close() ersetzt der Browser die Originaldatei atomar durch den neuen Inhalt. Wird der Stream mit abort() abgebrochen oder nie geschlossen, bleibt die Originaldatei unverändert.

Standardmäßig startet die temporäre Datei leer. Mit keepExistingData: true wird der bisherige Inhalt übernommen. Das braucht man, wenn man nur einzelne Bereiche ändern oder etwas anhängen möchte, zum Beispiel mit seek().

Bei Handles, die vom Nutzer gewählt wurden, fragt der Browser vor dem ersten Schreibzugriff nach der Berechtigung readwrite, sofern sie noch nicht erteilt ist.

Parameter

Name Typ Default Beschreibung
$options Object {} Optionales Einstellungsobjekt.
$options.keepExistingData boolean false Bei true wird der vorhandene Dateiinhalt in die temporäre Datei kopiert. Bei false startet der Stream mit einer leeren Datei.
$options.mode "siloed" | "exclusive" "siloed" Sperrmodus (nicht standardisiert, nur neuere Chromium-Versionen). Mit "siloed" sind mehrere Writer gleichzeitig erlaubt, und der zuletzt geschlossene gewinnt. "exclusive" erlaubt nur einen einzigen Writer.

Rückgabewert

Typ
Promise<FileSystemWritableFileStream>
Beschreibung
Ein Promise, das zu einem FileSystemWritableFileStream für die Datei aufgelöst wird.

Beispiele

Text über den Speichern-Dialog in eine Datei schreiben

const saveText = async (text) => {
  const handle = await window.showSaveFilePicker({
    suggestedName: 'notizen.txt',
    types: [{ description: 'Textdatei', accept: { 'text/plain': ['.txt'] } }]
  });
  const writable = await handle.createWritable();
  await writable.write(text);
  await writable.close(); // erst jetzt wird die Datei wirklich ersetzt
  console.log(`Gespeichert: ${handle.name}`);
};

document.querySelector('#save').addEventListener('click', () => saveText('Hallo Welt!'));
Gespeichert: notizen.txt

An eine bestehende Datei im OPFS anhängen

const appendLog = async (line) => {
  const root = await navigator.storage.getDirectory();
  const handle = await root.getFileHandle('app.log', { create: true });
  const file = await handle.getFile();

  const writable = await handle.createWritable({ keepExistingData: true });
  await writable.seek(file.size); // ans Dateiende springen
  await writable.write(`${new Date().toISOString()} ${line}\n`);
  await writable.close();

  const updated = await handle.getFile();
  console.log(await updated.text());
};

await appendLog('App gestartet');
2024-05-01T10:00:00.000Z App gestartet

Fehlerbehandlung und Abbruch ohne Datenverlust

const safeWrite = async (handle, data) => {
  const writable = await handle.createWritable();
  try {
    await writable.write({ type: 'write', position: 0, data });
    await writable.truncate(data.length);
    await writable.close();
  } catch (err) {
    await writable.abort(); // Originaldatei bleibt unverändert
    console.error('Schreiben fehlgeschlagen:', err.name);
  }
};

Fetch-Antwort per Stream direkt in eine Datei leiten

const download = async (url) => {
  const handle = await window.showSaveFilePicker({ suggestedName: 'download.bin' });
  const writable = await handle.createWritable();
  const response = await fetch(url);
  // pipeTo schließt den Stream am Ende automatisch
  await response.body.pipeTo(writable);
  console.log('Download abgeschlossen');
};
Download abgeschlossen

// Wichtig · Fallstricke

  • Ohne close() wird nichts gespeichert. Solange der Stream nicht geschlossen ist, bleiben alle Änderungen in der temporären Datei. pipeTo() schließt den Stream automatisch.
  • Ohne keepExistingData: true wird die Datei vollständig überschrieben. Das ist ein häufiger Grund für versehentlich geleerte Dateien.
  • Browser-Unterstützung: Chromium-Browser unterstützen die Methode für Dateien vom Nutzer und für OPFS. Firefox (ab 111) und Safari unterstützen sie nur im OPFS, denn showSaveFilePicker() und showOpenFilePicker() fehlen dort. Deshalb vorher die Unterstützung prüfen, z. B. mit 'createWritable' in FileSystemFileHandle.prototype.
  • Die Methode funktioniert nur in sicheren Kontexten (HTTPS). Für nutzergewählte Dateien ist außerdem eine Nutzeraktion nötig, damit die Berechtigung angefragt werden kann.
  • Mögliche Fehler: NotAllowedError (Berechtigung verweigert), NotFoundError (Datei existiert nicht mehr), NoModificationAllowedError (Datei gesperrt, z. B. durch einen exclusive-Writer oder ein offenes FileSystemSyncAccessHandle), QuotaExceededError (Speicherplatz erschöpft).
  • Leistung: Weil in eine temporäre Kopie geschrieben wird, sind häufige kleine Änderungen an großen Dateien teuer. Im OPFS und in Web Workern ist dafür createSyncAccessHandle() deutlich schneller.