Start · Sprachen · JavaScript · Referenz · FileSystemDirectoryReader

FileSystemDirectoryReader

Schnittstelle

Liest die Einträge eines Verzeichnisses (<code>FileSystemFileEntry</code> bzw. <code>FileSystemDirectoryEntry</code>) aus der File and Directory Entries API stapelweise aus.

seit JavaScript Baseline: alle modernen Browser (Chrome, Edge, Fir Kategorie: webapi

Signatur

interface FileSystemDirectoryReader

Beschreibung

Das Interface FileSystemDirectoryReader gehört zur File and Directory Entries API. Ein Objekt davon bekommen Sie über FileSystemDirectoryEntry.createReader(). Damit können Sie den Inhalt eines Verzeichnisses auflisten. Jeder Eintrag ist entweder eine Datei (FileSystemFileEntry) oder ein Unterverzeichnis (FileSystemDirectoryEntry).

Typischerweise nutzen Sie das Interface beim Drag & Drop ganzer Ordner (über DataTransferItem.webkitGetAsEntry()) oder bei einem <input type="file" webkitdirectory>. So können Sie Ordnerstrukturen rekursiv durchlaufen, zum Beispiel für einen Upload, der die Verzeichnisstruktur beibehält.

Das Interface hat nur eine Methode: readEntries(successCallback, errorCallback). Wichtig ist: Ein einzelner Aufruf liefert nicht unbedingt alle Einträge. Chrome gibt zum Beispiel höchstens 100 Einträge pro Aufruf zurück. Sie müssen readEntries() deshalb so oft aufrufen, bis ein leeres Array zurückkommt.

Die API arbeitet mit Callbacks und nicht mit Promises. In der Praxis verpackt man readEntries() meist in ein Promise, damit man async/await nutzen kann.

Parameter

Name Typ Default Beschreibung
$successCallback Pflicht (entries: FileSystemEntry[]) => void Parameter von readEntries(): Wird mit einem Array der nächsten Einträge aufgerufen. Ein leeres Array bedeutet, dass alle Einträge gelesen wurden.
$errorCallback (error: DOMException) => void Parameter von readEntries(): Wird bei einem Fehler aufgerufen, z. B. wenn das Lesen des Verzeichnisses fehlschlägt (NotFoundError, SecurityError).

Beispiele

Reader erzeugen und einen Ordner per Drag & Drop einlesen

const dropZone = document.querySelector('#drop-zone');

dropZone.addEventListener('dragover', (e) => e.preventDefault());

dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  const entry = e.dataTransfer.items[0]?.webkitGetAsEntry();
  if (!entry?.isDirectory) return;

  // FileSystemDirectoryReader erzeugen
  const reader = entry.createReader();
  reader.readEntries(
    (entries) => {
      for (const item of entries) {
        console.log(item.isDirectory ? '📁' : '📄', item.name);
      }
    },
    (err) => console.error('Lesefehler:', err.name)
  );
});
📁 bilder 📄 index.html 📄 style.css

Alle Einträge vollständig lesen (Promise-Wrapper mit Schleife)

const readBatch = (reader) =>
  new Promise((resolve, reject) => reader.readEntries(resolve, reject));

const readAllEntries = async (dirEntry) => {
  const reader = dirEntry.createReader();
  const all = [];
  let batch;
  // So lange lesen, bis ein leeres Array kommt (Chrome: max. 100 pro Aufruf)
  do {
    batch = await readBatch(reader);
    all.push(...batch);
  } while (batch.length > 0);
  return all;
};

// Verwendung im drop-Handler:
// const entries = await readAllEntries(entry);
// console.log(`${entries.length} Einträge gefunden`);
250 Einträge gefunden

Ordnerstruktur rekursiv in File-Objekte umwandeln

const readBatch = (reader) =>
  new Promise((resolve, reject) => reader.readEntries(resolve, reject));

const getFile = (fileEntry) =>
  new Promise((resolve, reject) => fileEntry.file(resolve, reject));

const collectFiles = async (entry) => {
  if (entry.isFile) {
    const file = await getFile(entry);
    return [{ path: entry.fullPath, file }];
  }
  const reader = entry.createReader();
  const result = [];
  let batch;
  do {
    batch = await readBatch(reader);
    for (const child of batch) {
      result.push(...(await collectFiles(child)));
    }
  } while (batch.length > 0);
  return result;
};

document.querySelector('#drop-zone').addEventListener('drop', async (e) => {
  e.preventDefault();
  const root = e.dataTransfer.items[0].webkitGetAsEntry();
  const files = await collectFiles(root);
  files.forEach(({ path, file }) => console.log(path, file.size));
});
/projekt/index.html 1024 /projekt/bilder/logo.png 20480

// Wichtig · Fallstricke

  • Häufigster Fehler: readEntries() nur einmal aufrufen. Dann fehlen bei großen Ordnern Einträge, weil Chrome/Edge höchstens 100 pro Aufruf liefern. Rufen Sie die Methode immer so lange auf, bis ein leeres Array zurückkommt.
  • Rufen Sie readEntries() auf demselben Reader nicht parallel auf. Warten Sie auf jeden Callback, bevor Sie den nächsten Aufruf starten. Sonst gibt es einen InvalidStateError.
  • Greifen Sie im drop-Handler synchron auf dataTransfer.items und webkitGetAsEntry() zu. Nach dem ersten await ist die DataTransfer-Liste leer.
  • Die API ist inzwischen in allen modernen Browsern verfügbar. Der Einstiegspunkt webkitGetAsEntry() hat aber aus historischen Gründen noch das Präfix. Die veraltete Variante requestFileSystem() gibt es nur in Chromium, und sie ist nicht standardisiert.
  • Die Einträge sind schreibgeschützt. Für Lese- und Schreibzugriff auf echte Verzeichnisse ist die neuere File System Access API (FileSystemDirectoryHandle, showDirectoryPicker()) gedacht. Sie bietet Promises und asynchrone Iteratoren, wird aber nicht von allen Browsern unterstützt.
  • Die Reihenfolge der Einträge ist nicht festgelegt. Sortieren Sie bei Bedarf selbst, z. B. nach name.