Start · Sprachen · JavaScript · Referenz · Window.showSaveFilePicker()

Window.showSaveFilePicker()

Methode

Öffnet einen nativen Speichern-Dialog und liefert ein Promise mit einem <code>FileSystemFileHandle</code> für die gewählte Zieldatei.

seit JavaScript Chromium 86+ (Chrome, Edge, Opera); nicht in Firef Kategorie: webapi

Signatur

Window.showSaveFilePicker(options)

Beschreibung

window.showSaveFilePicker() gehört zur File System Access API. Die Methode öffnet den Speichern-Dialog des Betriebssystems. Wählt die Person einen Speicherort und einen Dateinamen, wird das Promise mit einem FileSystemFileHandle erfüllt. Über dessen Methode createWritable() schreibst du Daten direkt in die Datei auf dem Datenträger. Einen Download-Link über <a download> brauchst du dafür nicht.

Die Methode eignet sich für webbasierte Editoren, Zeichenprogramme, Tabellen-Werkzeuge und ähnliche Anwendungen mit echtem „Speichern unter …“. Das zurückgegebene Handle kannst du behalten, zum Beispiel in IndexedDB. Spätere Speichervorgänge schreiben dann in dieselbe Datei, ohne dass der Dialog erneut erscheint. Eventuell musst du vorher mit requestPermission() die Berechtigung neu anfordern.

Mit dem Parameter options steuerst du den Dialog:

  • suggestedName schlägt einen Dateinamen vor.
  • types legt erlaubte Dateitypen fest (MIME-Typ plus Dateiendungen).
  • startIn bestimmt den Startordner.
  • id sorgt dafür, dass sich der Browser den zuletzt benutzten Ordner pro Anwendungsfall merkt.

Die Methode funktioniert nur in einem sicheren Kontext (HTTPS oder localhost). Außerdem braucht sie eine Benutzeraktivierung, also zum Beispiel einen Klick.

Parameter

Name Typ Default Beschreibung
$options Object {} Konfigurationsobjekt für den Dialog. Mögliche Felder stehen in den folgenden Einträgen.
$options.suggestedName string Vorgeschlagener Dateiname, z. B. "bericht.txt".
$options.types Array<{description?: string, accept: Record<string, string[]>}> [] Erlaubte Dateitypen. accept ordnet MIME-Typen den Dateiendungen zu, z. B. { "text/plain": [".txt"] }.
$options.excludeAcceptAllOption boolean false Bei true fehlt im Dialog die Auswahl „Alle Dateien“.
$options.id string Kennung für den Anwendungsfall (max. 32 Zeichen, [A-Za-z0-9_-]). Der Browser merkt sich den zuletzt benutzten Ordner pro id.
$options.startIn FileSystemHandle|"desktop"|"documents"|"downloads"|"music"|"pictures"|"videos" Startordner des Dialogs: ein bekannter Systemordner oder ein vorhandenes Handle.

Rückgabewert

Typ
Promise<FileSystemFileHandle>
Beschreibung
Wird mit einem FileSystemFileHandle für die gewählte Datei erfüllt. Bricht die Person den Dialog ab, wird das Promise mit einem AbortError (DOMException) abgelehnt. Fehlt die Benutzeraktivierung, gibt es einen SecurityError. Bei ungültigen types gibt es einen TypeError.

Beispiele

Text als Datei speichern

const saveButton = document.querySelector('#save');

saveButton.addEventListener('click', async () => {
  try {
    const handle = await window.showSaveFilePicker({
      suggestedName: 'notizen.txt',
      types: [{
        description: 'Textdateien',
        accept: { 'text/plain': ['.txt'] }
      }]
    });

    const writable = await handle.createWritable();
    await writable.write('Hallo vom Web-Editor!');
    await writable.close(); // erst jetzt landen die Daten auf der Platte

    console.log(`Gespeichert als ${handle.name}`);
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('Speichern abgebrochen');
    } else {
      console.error(err);
    }
  }
});
Gespeichert als notizen.txt

JSON-Export mit Fallback für Firefox und Safari

const saveJson = async (data, fileName = 'export.json') => {
  const blob = new Blob([JSON.stringify(data, null, 2)], {
    type: 'application/json'
  });

  if ('showSaveFilePicker' in window) {
    const handle = await window.showSaveFilePicker({
      suggestedName: fileName,
      id: 'json-export',
      startIn: 'documents',
      types: [{
        description: 'JSON-Datei',
        accept: { 'application/json': ['.json'] }
      }]
    });
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
    return;
  }

  // Fallback: klassischer Download
  const url = URL.createObjectURL(blob);
  const a = Object.assign(document.createElement('a'), {
    href: url,
    download: fileName
  });
  a.click();
  URL.revokeObjectURL(url);
};

document.querySelector('#export').addEventListener('click', () =>
  saveJson({ nutzer: 'Anna', punkte: 42 })
);

„Speichern“ und „Speichern unter“ mit gemerktem Handle

let fileHandle = null;

const saveAs = async (content) => {
  fileHandle = await window.showSaveFilePicker({
    suggestedName: 'dokument.md',
    types: [{ description: 'Markdown', accept: { 'text/markdown': ['.md'] } }]
  });
  await save(content);
};

const save = async (content) => {
  if (!fileHandle) return saveAs(content);
  const writable = await fileHandle.createWritable();
  await writable.write(content);
  await writable.close();
  console.log('Datei aktualisiert:', fileHandle.name);
};

document.querySelector('#save').addEventListener('click', () =>
  save(document.querySelector('textarea').value)
);
Datei aktualisiert: dokument.md

// Wichtig · Fallstricke

  • Browser-Unterstützung: Die Methode gibt es nur in Chromium-basierten Desktop-Browsern (Chrome, Edge und Opera ab Version 86). Firefox, Safari und Android-Chrome unterstützen sie nicht. Prüfe deshalb immer mit 'showSaveFilePicker' in window, ob sie vorhanden ist, und biete einen Fallback über <a download> an.
  • Sicherer Kontext und Benutzeraktivierung: Die Methode läuft nur über HTTPS oder localhost. Sie muss direkt aus einer Nutzerinteraktion heraus aufgerufen werden, sonst gibt es einen SecurityError. In Cross-Origin-iframes ist sie gesperrt.
  • Abbruch behandeln: Schließt die Person den Dialog, wird das Promise mit einem AbortError abgelehnt. Fange diesen Fehler ab und zeige ihn nicht als echten Fehler an.
  • Schreibvorgang abschließen: createWritable() schreibt zunächst in eine temporäre Datei. Erst close() übernimmt die Änderungen in die Zieldatei. Vergisst du close(), bleibt die Datei leer bzw. unverändert.
  • Datei wird schon beim Auswählen angelegt: Die Zieldatei kann bereits entstehen oder geleert werden, sobald ein Ort gewählt ist, also noch bevor du Daten schreibst.
  • Gesperrte Orte: Systemordner und sensible Dateiendungen (z. B. .lnk, .exe) blockiert der Browser möglicherweise.
  • Der Standard ist ein WICG-Entwurf (kein W3C-Standard) und kann sich noch ändern.