К сожалению, ни один из существующих ответов не является полностью правильным, потому что readEntries
не обязательно вернет ALL (файл или каталог) записи для данного каталога. Это часть спецификации API (см. Раздел «Документация» ниже).
Чтобы на самом деле получить всех файлов, нам нужно будет повторно вызывать readEntries
(для каждого каталога, с которым мы сталкиваемся), пока он не вернёт пустой массив. Если мы этого не сделаем, мы пропустим некоторые файлы / подкаталоги в каталоге, например. в Chrome readEntries
будет возвращать не более 100 записей одновременно.
Использование Promises (await
/ async
) для более наглядной демонстрации правильного использования readEntries
(поскольку он асинхронный) и BFS для обхода структуры каталогов:
// Drop handler function to get all files
async function getAllFileEntries(dataTransferItemList) {
let fileEntries = [];
// Use BFS to traverse entire directory/file structure
let queue = [];
// Unfortunately dataTransferItemList is not iterable i.e. no forEach
for (let i = 0; i < dataTransferItemList.length; i++) {
queue.push(dataTransferItemList[i].webkitGetAsEntry());
}
while (queue.length > 0) {
let entry = queue.shift();
if (entry.isFile) {
fileEntries.push(entry);
} else if (entry.isDirectory) {
queue.push(...await readAllDirectoryEntries(entry.createReader()));
}
}
return fileEntries;
}
// Get all the entries (files or sub-directories) in a directory
// by calling readEntries until it returns empty array
async function readAllDirectoryEntries(directoryReader) {
let entries = [];
let readEntries = await readEntriesPromise(directoryReader);
while (readEntries.length > 0) {
entries.push(...readEntries);
readEntries = await readEntriesPromise(directoryReader);
}
return entries;
}
// Wrap readEntries in a promise to make working with readEntries easier
// readEntries will return only some of the entries in a directory
// e.g. Chrome returns at most 100 entries at a time
async function readEntriesPromise(directoryReader) {
try {
return await new Promise((resolve, reject) => {
directoryReader.readEntries(resolve, reject);
});
} catch (err) {
console.log(err);
}
}
Полный рабочий пример на Codepen: https://codepen.io/anon/pen/gBJrOP
FWIW Я взял это только потому, что при использовании принятого ответа я не возвращал все файлы, которые ожидал, в каталоге, содержащем 40 000 файлов (многие каталоги, содержащие более 100 файлов / подкаталогов).
Документация:
Это поведение описано в FileSystemDirectoryReader . Выдержка с добавлением акцента:
readEntries ()
Возвращает массив, содержащий некоторое число
записи справочника . Каждый элемент в массиве является объектом, основанным на
FileSystemEntry - обычно либо FileSystemFileEntry, либо
FileSystemDirectoryEntry.
Но, если честно, документация MDN могла бы прояснить это в других разделах. Документация readEntries () просто отмечает:
readEntries () метод извлекает записи каталога в читаемом каталоге и доставляет их в массиве в предоставленную функцию обратного вызова
И единственное упоминание / подсказка о необходимости нескольких вызовов - это описание параметра successCallback :
Если не осталось файлов или вы уже вызвали readEntries () в
это FileSystemDirectoryReader, массив пустой.
Возможно, API также может быть более интуитивно понятным, но, как отмечается в документации: это нестандартная / экспериментальная функция, не соответствующая стандартам, и от нее нельзя ожидать, что она будет работать во всех браузерах.
Похожие:
- johnozbay comments , что в Chrome
readEntries
вернет не более 100 записей для каталога (проверено как Chrome 64).
- Xan достаточно хорошо объясняет правильное использование
readEntries
в этом ответе (хотя и без кода).
- Ответ Пабло Баррии Уренды правильно вызывает
readEntries
в асинхронном режиме без BFS. Он также отмечает, что Firefox возвращает все записи в каталоге (в отличие от Chrome), но мы не можем полагаться на это, учитывая спецификацию.