Есть два основных способа сделать это. В асинхронной среде вы заметите, что есть два вида циклов: последовательный и параллельный. Последовательный цикл ожидает завершения одной итерации, прежде чем перейти к следующей итерации - это гарантирует, что каждая итерация цикла завершается по порядку. В параллельном цикле все итерации запускаются одновременно, и одну можно завершить раньше другой, однако это намного быстрее, чем последовательный цикл. Таким образом, в этом случае, вероятно, лучше использовать параллельный цикл, потому что не имеет значения, в каком порядке выполняется обход, до тех пор, пока он завершает и возвращает результаты (если вы не хотите, чтобы они были в порядке).
Параллельный цикл будет выглядеть так:
var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
Последовательный цикл будет выглядеть так:
var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
};
И чтобы проверить это в вашем домашнем каталоге (ВНИМАНИЕ: список результатов будет огромным, если у вас есть много вещей в вашем домашнем каталоге):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
РЕДАКТИРОВАТЬ: Улучшенные примеры.
file = dir + '/' + file;
Это не рекомендуется. Вы должны использовать:var path = require('path'); file = path.resolve(dir, file);
path.resolve(...)
вы получите правильный путь, будь вы в Windows или Unix :) Это означает, что вы получите что-то вродеC:\\some\\foo\\path
в Windows и/some/foo/path
в системах Unixrequire('node-dir').files(__dirname, function(err, files) { console.log(files); });
!--
синтаксис, был задан вопрос об этомЭтот использует максимальное количество новых, модных слов, доступных в узле 8, включая обещания, утилиту / обещание, деструктуризацию, асинхронное ожидание, отображение + уменьшение и многое другое, заставляя ваших коллег ломать голову, пытаясь выяснить, что происходит.
Узел 8+
Нет внешних зависимостей.
использование
Узел 10.10+
Обновлен для узла 10+ с еще большим количеством свиста:
Обратите внимание, что начиная с узла 11.15.0 вы можете использовать
files.flat()
вместо того,Array.prototype.concat(...files)
чтобы сгладить массив файлов.Узел 11+
Если вы хотите полностью взорвать голову, вы можете использовать следующую версию, используя асинхронные итераторы . Помимо того, что он действительно крут, он также позволяет потребителям получать результаты по одному за раз, что делает его более подходящим для действительно больших каталогов.
Использование изменилось, потому что возвращаемый тип теперь является асинхронным итератором, а не обещанием
Если кому-то интересно, я написал больше об асинхронных итераторах здесь: https://qwtel.com/posts/software/async-generators-in-the-wild/
источник
subdir
иsubdirs
вводит в заблуждение, так как это могут быть файлы (я предлагаю что-то вродеitemInDir
илиitem_in_dir
даже простоitem
вместо этого), но это решение кажется чище, чем принятый и гораздо меньше кода. Я также не нахожу это намного более сложным, чем код в принятом ответе. +1require(fs).promises
просто иutil.promisify
полностью отказаться . Лично я псевдоним fs к fs.promises.readdir
AKA объекту параметров, какreaddir(dir, {withFileTypes: true})
это, так что это вернет все элементы с информацией о их типе, поэтому нам вообще не нужно будет вызывать,stat
чтобы получить информацию, котораяreaddir
теперь дает нам обратно. Это избавляет нас от необходимости делать дополнительные системные вызовы. Подробности здесьwithFileTypes
. Спасибо за чаевые.return Array.prototype.concat(...files);
сlet result = Array.prototype.concat(...files); return result.map(file => file.split('\\').join('/'));
вами можем убедиться , что каталоги возвращают «/» , а не «\». Если вы не возражаете против регулярных выражений, вы также можете сделать этоreturn result.map(file => file.replace(/\\/g, '/'));
На всякий случай, если кто-нибудь найдет это полезным, я также собрал синхронную версию.
Совет: использовать меньше ресурсов при фильтрации. Фильтруйте внутри этой функции. Например, заменить
results.push(file);
приведенный ниже код. Отрегулируйте как требуется:источник
lstat
вместо? Или добавьте проверку рекурсивности, чтобы ограничить уровень рекурсивности.А. Посмотрите на файл модуля . У него есть функция, которая называется walk:
Это может быть для вас! И да, это асинхронно. Тем не менее, я думаю, что вам придется объединять полный путь самостоятельно, если вам они нужны.
Б. Альтернатива, и даже один из моих любимых: используйте
find
для этого Unix . Зачем опять что-то, что уже запрограммировано? Может быть, не совсем то, что вам нужно, но все же стоит проверить:Find имеет приятный встроенный механизм кэширования, который делает последующие поиски очень быстрыми, если изменилось только несколько папок.
источник
Еще один хороший пакет npm - это glob .
npm install glob
Он очень мощный и должен покрывать все ваши текущие потребности.
Редактировать:
Я на самом деле не был полностью доволен glob, поэтому я создал readdirp .
Я очень уверен, что его API делает рекурсивный поиск файлов и каталогов и применение определенных фильтров очень простым.
Прочитайте его документацию, чтобы получить лучшее представление о том, что он делает, и установите с помощью:
npm install readdirp
источник
Я рекомендую использовать node-glob для выполнения этой задачи.
источник
Если вы хотите использовать пакет npm, wrench довольно хорош.
РЕДАКТИРОВАТЬ (2018):
все, кто читал в последнее время: автор устарел этот пакет в 2015 году:
источник
denodify
это делаешь ? Обратный вызов запускается несколько раз (рекурсивно). Таким образом, использованиеQ.denodify(wrench.readdirRecursive)
возвращает только первый результат.Мне понравился ответ из chjj выше, и я не смог бы создать свою версию параллельного цикла без этого запуска.
Я также создал Gist . Комментарии приветствуются. Я все еще начинаю в сфере NodeJS, поэтому я надеюсь узнать больше.
источник
С рекурсией
призвание
источник
/
но с использованиемpath
модуля:path.join(searchPath, file)
. Таким образом, вы получите правильные пути независимо от ОС.Используйте node-dir, чтобы получить именно тот результат, который вам нравится
источник
Я кодировал это недавно, и подумал, что имеет смысл поделиться этим здесь. Код использует асинхронную библиотеку .
Вы можете использовать это так:
источник
Библиотека под названием Filehound является еще одним вариантом. Он будет рекурсивно искать данный каталог (рабочий каталог по умолчанию). Он поддерживает различные фильтры, обратные вызовы, обещания и синхронизируют поиски.
Например, ищите в текущем рабочем каталоге все файлы (используя обратные вызовы):
Или обещания и указание конкретного каталога:
Обратитесь к документации для дальнейших вариантов использования и примеров использования: https://github.com/nspragg/filehound
Отказ от ответственности: я автор.
источник
Используя async / await, это должно работать:
Вы можете использовать bluebird.Promisify или это:
Смотрите мой другой ответ для генератора подход, который может дать результаты еще быстрее.
источник
асинхронный
Синхронизация
Асинхронный читаемый
Примечание: обе версии будут следовать символическим ссылкам (так же, как оригинал
fs.readdir
)источник
Проверьте библиотеку final-fs . Это обеспечивает
readdirRecursive
функцию:источник
Автономная реализация обещаний
В этом примере я использую библиотеку обещаний when.js.
Я включил необязательный параметр,
includeDir
который будет включать каталоги в список файлов, если установлен вtrue
.источник
klaw и klaw-sync заслуживают внимания для такого рода вещей. Они были частью node-fs-extra .
источник
Вот еще одна реализация. Ни одно из приведенных выше решений не имеет каких-либо ограничений, и поэтому, если ваша структура каталогов велика, все они будут работать с перебоями и в конечном итоге исчерпать ресурсы.
Использование параллелизма 50 работает довольно хорошо и почти так же быстро, как и простые реализации для небольших структур каталогов.
источник
Модуль recursive-readdir обладает этой функциональностью.
источник
Я изменил ответ Trevor Senior's Promise для работы с Bluebird
источник
Для интереса, это потоковая версия, которая работает с потоковой библиотекой highland.js. В соавторстве с Виктором Ву.
источник
Используя Promises ( Q ), чтобы решить это в функциональном стиле:
Он возвращает обещание массива, поэтому вы можете использовать его как:
источник
Я должен добавить библиотеку Sander на основе Promise в список.
источник
Использование синей птицы обещаем.
источник
Поскольку каждый должен написать свое, я сделал один.
walk (dir, cb, endCb) cb (файл) endCb (err | null)
DIRTY
источник
проверить loaddir https://npmjs.org/package/loaddir
npm install loaddir
Вы можете использовать
fileName
вместо,baseName
если вам нужно расширение, а также.Дополнительным бонусом является то, что он будет также просматривать файлы и снова вызывать обратный вызов. Есть множество вариантов конфигурации, чтобы сделать его чрезвычайно гибким.
Я просто переделал
guard
драгоценный камень из рубина с помощью loaddir в течение короткого времениисточник
Это мой ответ. Надеюсь, это может кому-нибудь помочь.
Моя задача - сделать так, чтобы процедура поиска могла остановиться где угодно, а для найденного файла указывается относительная глубина по отношению к исходному пути.
источник
Вот рекурсивный метод получения всех файлов, включая подкаталоги.
источник
Еще один простой и полезный
источник
Вот как я использую функцию nodejs fs.readdir для рекурсивного поиска в каталоге.
Допустим, у вас есть путь с именем / database в корневом каталоге ваших проектов. Как только это обещание будет выполнено, оно должно выложить массив каждого файла в «/ database».
источник