Signatur
Beschreibung
showDirectoryPicker() gehört zur File System Access API. Die Methode öffnet den nativen Verzeichnisdialog des Betriebssystems. Wählt der Benutzer ein Verzeichnis aus, erhält die Webanwendung ein FileSystemDirectoryHandle. Damit kann sie den Inhalt des Verzeichnisses auflisten, Dateien und Unterordner öffnen und, wenn der Benutzer zustimmt, auch Dateien anlegen, schreiben oder löschen.
Typische Einsatzfälle sind Anwendungen, die ganze Projektordner bearbeiten, etwa Code-Editoren, Foto- oder Medienverwaltungen, Werkzeuge für statische Websites oder Synchronisations- und Backup-Tools. Im Gegensatz zu <input type="file" webkitdirectory> bekommt man keine einmalige Momentaufnahme, sondern einen dauerhaften Zugriff auf das echte Verzeichnis. Den Handle kann man sogar in IndexedDB speichern und in einer späteren Sitzung wiederverwenden.
Die Methode ist nur in einem sicheren Kontext (HTTPS oder localhost) verfügbar. Außerdem braucht sie eine vorübergehende Benutzeraktivierung: Sie muss direkt in einem Handler für eine Benutzeraktion aufgerufen werden, zum Beispiel bei einem Klick. Bricht der Benutzer den Dialog ab, wird das Promise mit einem AbortError abgelehnt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $options | Object | {} | Optionales Objekt zur Konfiguration des Dialogs. |
| $options.id | string | Bezeichner mit höchstens 32 Zeichen ([A-Za-z0-9_-]). Der Browser merkt sich für jede id das zuletzt verwendete Verzeichnis und öffnet den Dialog beim nächsten Mal wieder dort. |
|
| $options.mode | "read" | "readwrite" | "read" | Angeforderte Berechtigung. Bei "readwrite" fragt der Browser direkt nach der Schreiberlaubnis. |
| $options.startIn | FileSystemHandle | "desktop" | "documents" | "downloads" | "music" | "pictures" | "videos" | Startort des Dialogs: entweder ein bekanntes Systemverzeichnis oder ein vorhandener Handle. Bei einem Datei-Handle startet der Dialog in dessen übergeordnetem Ordner. |
Rückgabewert
FileSystemDirectoryHandle für das gewählte Verzeichnis erfüllt wird. Abgelehnt wird es mit AbortError (Dialog abgebrochen), SecurityError (fehlende Benutzeraktivierung, unsicherer Kontext oder Cross-Origin-iframe) oder TypeError (ungültige Optionen).Beispiele
Verzeichnis wählen und Inhalt auflisten
const button = document.querySelector('#ordner-waehlen');
button.addEventListener('click', async () => {
if (!('showDirectoryPicker' in window)) {
alert('Ihr Browser unterstützt die File System Access API nicht.');
return;
}
try {
const dirHandle = await window.showDirectoryPicker();
console.log(`Gewählter Ordner: ${dirHandle.name}`);
for await (const [name, handle] of dirHandle.entries()) {
console.log(handle.kind === 'directory' ? `📁 ${name}` : `📄 ${name}`);
}
} catch (err) {
if (err.name === 'AbortError') {
console.log('Auswahl abgebrochen.');
} else {
console.error(err);
}
}
});
Mit Schreibrecht eine Datei im Ordner anlegen
document.querySelector('#export').addEventListener('click', async () => {
const dirHandle = await window.showDirectoryPicker({
id: 'export-ordner',
mode: 'readwrite',
startIn: 'documents'
});
const fileHandle = await dirHandle.getFileHandle('bericht.json', { create: true });
const writable = await fileHandle.createWritable();
await writable.write(JSON.stringify({ erstellt: new Date().toISOString() }, null, 2));
await writable.close();
console.log(`bericht.json in "${dirHandle.name}" gespeichert.`);
});
Alle Dateien rekursiv durchlaufen und Gesamtgröße berechnen
const berechneGroesse = async (dirHandle) => {
let summe = 0;
for await (const handle of dirHandle.values()) {
if (handle.kind === 'file') {
const file = await handle.getFile();
summe += file.size;
} else {
summe += await berechneGroesse(handle);
}
}
return summe;
};
document.querySelector('#analyse').addEventListener('click', async () => {
const dir = await window.showDirectoryPicker();
const bytes = await berechneGroesse(dir);
console.log(`${dir.name}: ${(bytes / 1024 / 1024).toFixed(2)} MB`);
});
Berechtigung für einen gespeicherten Handle erneut prüfen
// dirHandle wurde z. B. aus IndexedDB geladen
const sicherstellenSchreibrecht = async (dirHandle) => {
const opts = { mode: 'readwrite' };
if ((await dirHandle.queryPermission(opts)) === 'granted') return true;
// requestPermission erfordert ebenfalls eine Benutzeraktion
return (await dirHandle.requestPermission(opts)) === 'granted';
};
// Wichtig · Fallstricke
- Browser-Kompatibilität: Nur Chromium-Browser ab Version 86 (Chrome, Edge, Opera) unterstützen die Methode, und zwar nur auf dem Desktop. Firefox und Safari bieten sie nicht an; sie unterstützen nur das Origin Private File System über
navigator.storage.getDirectory(). Prüfen Sie die Unterstützung vorab mit'showDirectoryPicker' in windowund bieten Sie als Ausweichlösung<input type="file" webkitdirectory>an. - Benutzeraktivierung: Wird die Methode ohne direkte Benutzeraktion aufgerufen, etwa beim Laden der Seite oder nach einem langen
await, wirft sie einenSecurityError. - iframes: In Cross-Origin-iframes ist der Aufruf blockiert.
- Gesperrte Verzeichnisse: Systemordner und sensible Orte wie das Home-Wurzelverzeichnis,
C:\Windowsoder der Profilordner des Browsers lehnt der Browser ab oder zeigt dafür eine Warnung. - Berechtigungen sind nicht dauerhaft: Ein in IndexedDB gespeicherter Handle behält seine Berechtigung meist nicht über Sitzungen hinweg. Prüfen Sie sie mit
queryPermission()und fordern Sie sie bei Bedarf mitrequestPermission()neu an. - Sicherheit: Mit Schreibzugriff kann die Anwendung Benutzerdaten verändern oder löschen. Fordern Sie
mode: 'readwrite'nur an, wenn Sie ihn wirklich brauchen, und behandeln Sie Dateinamen aus dem Verzeichnis als nicht vertrauenswürdige Eingabe, z. B. nicht ungeprüft perinnerHTMLausgeben.