Signatur
Beschreibung
Die schreibgeschützte Eigenschaft isFile des Interfaces FileSystemEntry gibt an, ob der Eintrag eine Datei ist. Ist der Wert true, handelt es sich um ein FileSystemFileEntry. Dann steht die Methode file() zur Verfügung, mit der man an das eigentliche File-Objekt kommt.
Gebraucht wird die Eigenschaft vor allem bei Drag & Drop. Über DataTransferItem.webkitGetAsEntry() bekommt man zu jedem abgelegten Element einen FileSystemEntry. Ob das eine Datei oder ein Ordner ist, weiß man vorher nicht. Mit isFile bzw. dem Gegenstück isDirectory entscheidet man, ob man die Datei direkt einliest oder das Verzeichnis mit einem FileSystemDirectoryReader rekursiv durchläuft.
Ein Eintrag ist immer entweder Datei oder Verzeichnis. isFile und isDirectory schließen sich also gegenseitig aus. Die Prüfung ist eine sichere Alternative zu instanceof FileSystemFileEntry, das in manchen Browsern nicht zuverlässig funktioniert.
Rückgabewert
true, wenn der Eintrag eine Datei ist, sonst false.Beispiele
Abgelegte Elemente nach Datei und Ordner unterscheiden
const dropZone = document.querySelector('#drop-zone');
dropZone.addEventListener('dragover', (e) => e.preventDefault());
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
for (const item of e.dataTransfer.items) {
const entry = item.webkitGetAsEntry();
if (!entry) continue;
if (entry.isFile) {
console.log(`Datei: ${entry.name}`);
} else if (entry.isDirectory) {
console.log(`Ordner: ${entry.name}`);
}
}
});
File-Objekt aus einem Datei-Eintrag lesen
// Wandelt den callback-basierten file()-Aufruf in ein Promise um
const entryToFile = (entry) =>
new Promise((resolve, reject) => {
if (!entry.isFile) {
reject(new TypeError(`${entry.name} ist keine Datei`));
return;
}
entry.file(resolve, reject);
});
document.querySelector('#drop-zone').addEventListener('drop', async (e) => {
e.preventDefault();
const entry = e.dataTransfer.items[0]?.webkitGetAsEntry();
if (!entry) return;
try {
const file = await entryToFile(entry);
console.log(file.name, file.size, 'Bytes');
} catch (err) {
console.warn(err.message);
}
});
Verzeichnisbaum rekursiv nach Dateien durchsuchen
const readAllEntries = (reader) =>
new Promise((resolve, reject) => {
const all = [];
const next = () =>
reader.readEntries((batch) => {
if (batch.length === 0) return resolve(all);
all.push(...batch);
next(); // readEntries liefert Ergebnisse evtl. in mehreren Teilen
}, reject);
next();
});
const collectFiles = async (entry) => {
if (entry.isFile) return [entry.fullPath];
const children = await readAllEntries(entry.createReader());
const nested = await Promise.all(children.map(collectFiles));
return nested.flat();
};
document.querySelector('#drop-zone').addEventListener('drop', async (e) => {
e.preventDefault();
const entries = [...e.dataTransfer.items]
.map((item) => item.webkitGetAsEntry())
.filter(Boolean);
const paths = (await Promise.all(entries.map(collectFiles))).flat();
console.log(paths);
});
// Wichtig · Fallstricke
- Nur lesbar: Wenn man
isFileeinen Wert zuweist, passiert nichts. Im Strict Mode wird einTypeErrorausgelöst. - Einträge sofort abrufen:
webkitGetAsEntry()muss innerhalb desdrop-Handlers synchron aufgerufen werden. Nach einemawaitist dieDataTransferItemListbereits leer. - Kompatibilität: Die File and Directory Entries API wird in Chrome, Edge, Firefox und Safari unterstützt, ist aber nicht standardisiert.
webkitGetAsEntry()heißt auch in Firefox so, mit dem Präfix. Für neue Projekte mit Schreibzugriff sollte man sich die File System Access API ansehen (FileSystemHandle.kindmit den Werten"file"und"directory"). - Auch mit
<input type="file" webkitdirectory>bekommt man keine Einträge, sondern direktFile-Objekte.isFileist dort nicht verfügbar. - Symbolische Links und Sonderdateien stellt der Browser je nach Betriebssystem unterschiedlich dar. Man sollte sich also nicht darauf verlassen, dass
isFileundisDirectorybei solchen Einträgen einheitlich ausfallen.