Start · Sprachen · JavaScript · Referenz · FileSystem

FileSystem

Schnittstelle

Stellt im File and Directory Entries API ein Dateisystem dar und bietet über <code>name</code> und <code>root</code> Zugriff auf dessen Namen und Wurzelverzeichnis.

seit JavaScript Baseline: alle modernen Browser (File and Director Kategorie: webapi

Signatur

interface FileSystem

Beschreibung

Die Schnittstelle FileSystem gehört zum File and Directory Entries API und steht für ein Dateisystem, in dem die zugehörigen FileSystemEntry-Objekte liegen. Selbst erzeugt man sie nicht. Man bekommt sie über die Eigenschaft filesystem eines Eintrags, meist wenn Nutzer Dateien oder Ordner per Drag & Drop ablegen (DataTransferItem.webkitGetAsEntry()) oder über ein <input type="file" webkitdirectory> auswählen (HTMLInputElement.webkitEntries).

Die Schnittstelle hat nur zwei schreibgeschützte Eigenschaften:

  • FileSystem.name: ein string mit einem vom Browser vergebenen, eindeutigen Namen des Dateisystems.
  • FileSystem.root: ein FileSystemDirectoryEntry, der das Wurzelverzeichnis darstellt. Von dort aus kann man mit createReader(), getFile() und getDirectory() durch die Struktur gehen.

Praktisch nutzt man FileSystem vor allem, um abgelegte Ordner rekursiv zu durchlaufen, etwa für Upload-Funktionen, die ganze Verzeichnisbäume samt relativer Pfade übernehmen sollen. Die Dateisysteme, die man so erhält, sind nur lesbar und zeigen nur die Dateien, die der Nutzer freigegeben hat.

Rückgabewert

Typ
FileSystem
Beschreibung
Eine Instanz bekommt man über FileSystemEntry.filesystem. Sie hat die Eigenschaften name (string) und root (FileSystemDirectoryEntry).

Beispiele

FileSystem aus einem Drag-&-Drop-Eintrag lesen

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

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

dropZone.addEventListener('drop', (event) => {
  event.preventDefault();
  // Einträge synchron im Handler holen, danach ist DataTransfer leer
  for (const item of event.dataTransfer.items) {
    const entry = item.webkitGetAsEntry();
    if (!entry) continue;
    const fs = entry.filesystem;
    console.log('Dateisystem:', fs.name);
    console.log('Wurzel:', fs.root.fullPath);
    console.log('Eintrag:', entry.fullPath, entry.isDirectory ? '(Ordner)' : '(Datei)');
  }
});
Dateisystem: <browserabhängiger Name> Wurzel: / Eintrag: /Projekt (Ordner)

Wurzelverzeichnis vollständig auslesen (readEntries in Schleife)

// readEntries liefert Ergebnisse in Teilen, also so lange aufrufen, bis ein leeres Array kommt
const readAllEntries = (dirEntry) => new Promise((resolve, reject) => {
  const reader = dirEntry.createReader();
  const all = [];
  const readBatch = () => {
    reader.readEntries((batch) => {
      if (batch.length === 0) return resolve(all);
      all.push(...batch);
      readBatch();
    }, reject);
  };
  readBatch();
});

const listRoot = async (fileSystem) => {
  const entries = await readAllEntries(fileSystem.root);
  entries.forEach((e) => console.log(e.isFile ? '📄' : '📁', e.fullPath));
};

// Nutzung, z. B. im drop-Handler: listRoot(entry.filesystem);
📁 /Projekt

Ordnerbaum rekursiv in File-Objekte umwandeln

const getFile = (fileEntry) => new Promise((res, rej) => fileEntry.file(res, rej));

const readDir = (dirEntry) => new Promise((resolve, reject) => {
  const reader = dirEntry.createReader();
  const all = [];
  const next = () => reader.readEntries((b) => {
    if (!b.length) return resolve(all);
    all.push(...b);
    next();
  }, reject);
  next();
});

const collectFiles = async (entry, result = []) => {
  if (entry.isFile) {
    result.push({ path: entry.fullPath, file: await getFile(entry) });
  } else if (entry.isDirectory) {
    for (const child of await readDir(entry)) {
      await collectFiles(child, result);
    }
  }
  return result;
};

document.querySelector('#drop-zone').addEventListener('drop', async (event) => {
  event.preventDefault();
  const entries = [...event.dataTransfer.items]
    .map((item) => item.webkitGetAsEntry())
    .filter(Boolean);
  for (const entry of entries) {
    const files = await collectFiles(entry.filesystem.root);
    files.forEach(({ path, file }) => console.log(path, file.size, 'Bytes'));
  }
});
/Projekt/index.html 1024 Bytes /Projekt/css/style.css 512 Bytes

// Wichtig · Fallstricke

  • Nicht verwechseln: FileSystem gehört zum älteren File and Directory Entries API und hat nichts mit dem neueren File System API zu tun (FileSystemHandle, showOpenFilePicker(), Origin Private File System über navigator.storage.getDirectory()). Für neue Anwendungen mit Schreibzugriff ist das neuere API die bessere Wahl.
  • Nur lesend: Dateisysteme aus Drag & Drop oder webkitdirectory lassen sich nicht beschreiben. Das früher in Chrome verfügbare sandboxed window.webkitRequestFileSystem() ist veraltet und nicht standardisiert.
  • Synchron zugreifen: webkitGetAsEntry() muss direkt im drop-Handler aufgerufen werden, also vor dem ersten await. Danach ist dataTransfer.items leer.
  • readEntries() liefert Teilergebnisse: Chrome gibt z. B. höchstens 100 Einträge pro Aufruf zurück. Deshalb so lange aufrufen, bis ein leeres Array kommt.
  • Callback-basiert: Das API nutzt Callbacks statt Promises. Für async/await muss man die Aufrufe selbst in Promises verpacken.
  • Kompatibilität: Wird von Chrome, Edge, Firefox und Safari unterstützt, der Zugang läuft aber teils nur über Methoden mit webkit-Präfix. Der Wert von name hängt vom Browser ab, man sollte sich nicht auf ihn verlassen.