Start · Sprachen · JavaScript · Referenz · FileSystemEntry

FileSystemEntry

Schnittstelle

Stellt einen einzelnen Eintrag (Datei oder Verzeichnis) in einem Dateisystem der File and Directory Entries API dar, etwa bei Drag & Drop.

seit JavaScript Baseline: alle modernen Browser (Chrome 8+, Firefo Kategorie: webapi

Signatur

interface FileSystemEntry

Beschreibung

FileSystemEntry ist die abstrakte Basisschnittstelle der File and Directory Entries API. Sie steht für einen einzelnen Eintrag in einem (virtuellen) Dateisystem. Direkt instanziieren kann man sie nicht. Man bekommt immer eine der beiden Unterklassen: FileSystemFileEntry für Dateien oder FileSystemDirectoryEntry für Verzeichnisse.

Heute braucht man sie vor allem bei Drag & Drop von Ordnern. Über DataTransferItem.webkitGetAsEntry() wird aus jedem abgelegten Element ein FileSystemEntry, und damit lassen sich Verzeichnisbäume rekursiv durchlaufen. Mit <input type="file" webkitdirectory> kommt man über HTMLInputElement.webkitEntries an dieselben Einträge.

Wichtige Eigenschaften:

  • isFile / isDirectory: boolean, gibt an, um welche Art Eintrag es sich handelt.
  • name: Name des Eintrags ohne Pfad.
  • fullPath: absoluter Pfad relativ zur Wurzel des Dateisystems, z. B. /fotos/urlaub.jpg.
  • filesystem: das zugehörige FileSystem-Objekt.

Die Methode getParent(successCallback, errorCallback) liefert das übergeordnete Verzeichnis. Die API arbeitet ausschließlich mit Callbacks und nicht mit Promises. In modernem Code verpackt man sie deshalb meist selbst in Promises.

Parameter

Name Typ Default Beschreibung
$successCallback (parent: FileSystemDirectoryEntry) => void Nur bei getParent(): Wird mit dem übergeordneten FileSystemDirectoryEntry aufgerufen.
$errorCallback (error: DOMException) => void Nur bei getParent(): Wird bei einem Fehler aufgerufen, z. B. mit NotFoundError oder SecurityError.

Rückgabewert

Typ
FileSystemFileEntry | FileSystemDirectoryEntry
Beschreibung
Das Interface selbst gibt nichts zurück. Man arbeitet immer mit Instanzen der Unterklassen, die z. B. DataTransferItem.webkitGetAsEntry() liefert. getParent() gibt undefined zurück, das Ergebnis kommt über den Callback.

Beispiele

Einträge aus Drag & Drop auslesen

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

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

dropZone.addEventListener('drop', (e) => {
  e.preventDefault();
  for (const item of e.dataTransfer.items) {
    // Liefert FileSystemFileEntry oder FileSystemDirectoryEntry
    const entry = item.webkitGetAsEntry();
    if (!entry) continue;
    console.log(entry.name, entry.isDirectory ? '(Ordner)' : '(Datei)', entry.fullPath);
  }
});
fotos (Ordner) /fotos notiz.txt (Datei) /notiz.txt

Ordner rekursiv durchlaufen (Callback-API als Promise)

const readEntries = (dirEntry) => new Promise((resolve, reject) => {
  const reader = dirEntry.createReader();
  const all = [];
  // readEntries liefert Ergebnisse stückweise, darum so lange lesen, bis ein leeres Array kommt
  const readBatch = () => reader.readEntries((batch) => {
    if (batch.length === 0) return resolve(all);
    all.push(...batch);
    readBatch();
  }, reject);
  readBatch();
});

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, size: file.size }];
  }
  const children = await readEntries(entry);
  const nested = await Promise.all(children.map(collectFiles));
  return nested.flat();
};

document.querySelector('#drop').addEventListener('drop', async (e) => {
  e.preventDefault();
  // Einträge synchron holen, bevor das DataTransfer-Objekt ungültig wird
  const entries = [...e.dataTransfer.items]
    .map((item) => item.webkitGetAsEntry())
    .filter(Boolean);
  const files = (await Promise.all(entries.map(collectFiles))).flat();
  console.table(files);
});
Tabelle mit path und size aller Dateien, z. B. /fotos/a.jpg | 204800

Übergeordnetes Verzeichnis mit getParent()

const getParent = (entry) => new Promise((resolve, reject) => entry.getParent(resolve, reject));

const showParent = async (entry) => {
  try {
    const parent = await getParent(entry);
    console.log(`${entry.name} liegt in ${parent.fullPath}`);
  } catch (err) {
    console.error('Kein Zugriff:', err.name);
  }
};
a.jpg liegt in /fotos

// Wichtig · Fallstricke

  • Kein Konstruktor: new FileSystemEntry() wirft einen TypeError. Instanzen bekommt man nur über die API selbst.
  • DataTransfer ist nur kurz gültig: webkitGetAsEntry() muss synchron im drop-Handler aufgerufen werden. Nach einem await ist die items-Liste leer.
  • readEntries() liefert Ergebnisse stückweise (in Chrome höchstens 100 pro Aufruf). Man muss so lange weiterlesen, bis ein leeres Array zurückkommt, sonst fehlen Dateien.
  • Präfix trotz Standard: Die Methoden heißen browserübergreifend weiterhin webkitGetAsEntry() und webkitEntries. Firefox und Safari unterstützen diese Namen ebenfalls.
  • Die Eigenschaft filesystem und getParent() funktionieren bei Drag & Drop nur eingeschränkt. Man kann nicht über den abgelegten Ordner hinaus nach oben navigieren.
  • Die API ist nur lesend. Zum Schreiben auf die Festplatte gibt es die neuere File System Access API (FileSystemHandle, showOpenFilePicker()), die derzeit aber nur Chromium-Browser vollständig unterstützen. Für den Zugriff auf lokale Dateien sind die beiden APIs nicht untereinander kompatibel.
  • Methoden, die nur in Chrome existieren und nicht standardisiert sind, etwa copyTo(), moveTo(), remove() und getMetadata(), sollte man nicht verwenden.