Signatur
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
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!'));
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');
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');
};
// 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: truewird 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()undshowOpenFilePicker()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 einenexclusive-Writer oder ein offenesFileSystemSyncAccessHandle),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.