Как рекурсивно читать каталог в Node.js

Либо для создания какого-либо алгоритма поиска файлов, либо для получения списка всех файлов и папок в каталоге, чтобы сжать его с помощью zlib, эту функцию часто ищут разработчики Node.js (а также число загрузок и зависимых пакетов в некоторых известные модули это доказывают).

В этой статье мы собираемся показать вам, как выполнить рекурсивный цикл по каталогу, чтобы вывести список всего его содержимого с помощью 3 различных методов (пользовательских фрагментов или с помощью модулей с открытым исходным кодом).

А. Использование пользовательского фрагмента

Если вы хотите выполнить рекурсивный цикл по каталогу в Node.js, вам не обязательно иметь модуль для его достижения, поскольку вы можете использовать очень простую рекурсивную функцию. Следующие filewalker Функция поможет вам. В качестве первого аргумента он ожидает строку с путем к папке, которая будет рекурсивно исследована, а в качестве второго аргумента — функцию (обратный вызов), выполняемую, если в указанном пути нет директорий mores. Обратный вызов получает 2 аргумента, ошибку как первую и массив результатов, который содержит все смешанные пути файлов и подкаталогов.

Заметка

Если вам нужно только игнорировать все папки и получить только пути к файлам, вы можете легко прокомментировать строку, которая хранит путь к файлу в массиве внутри фрагмента.

const fs = require('fs');
const path = require('path');
/**
* Explores recursively a directory and returns all the filepaths and folderpaths in the callback.
*
* @see http://stackoverflow.com/a/5827895/4241030
* @param {String} dir
* @param {Function} done
*/
function filewalker(dir, done) {
let 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 directory, execute a recursive call
if (stat && stat.isDirectory()) {
// Add directory to array [comment if you need to remove the directories from the array]
results.push(file);
filewalker(file, function(err, res){
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};

И его использование очень просто:

filewalker("./some-existent-path", function(err, data){
if(err){
throw err;
}
// ["c://some-existent-path/file.txt","c:/some-existent-path/subfolder"]
console.log(data);
});

Это решение идеально, если вы не хотите полагаться на модуль для достижения чего-то очень простого и прямо в вашем коде.

Б. Использование модуля readdirp

Если ваш код не так прост, то решение с одним фрагментом может быть недостаточно для вас из-за сложности вашего кода. В этом случае вы можете использовать readdirp модуль, да readdirp не readdir, readdirp — очень полезный модуль, который предоставляет рекурсивную версию readdir Функция доступна в модуле файловой системы Node.js, кроме того, она предоставляет поток API.

Чтобы установить этот модуль в свой проект, выполните следующую команду в своем терминале:

npm install readdirp

Преимущества использования этого модуля очень очевидны, и это не так просто, как первое решение, которое мы представили в этой статье. Этот модуль позволяет вам фильтровать рекурсивное исследование по расширению файла и по имени каталога, кроме того, он позволяет вам задавать глубину (максимальное значение вложенных папок для исследования в предоставленном каталоге). Он работает следующим образом, вам нужно, чтобы модуль readdirp был в основном функцией. С помощью этой функции вы сможете рекурсивно выполнять итерацию по пути к папке, для этого требуется объект, который задает параметры, Вы можете увидеть все доступные опции readdirp здесь:

var settings = {
root: './a-folder-to-explore',
entryType: 'all',
// Filter files with js and json extension
fileFilter: [ '*.js', '*.json' ],
// Filter by directory
directoryFilter: [ '!.git', '!*modules' ],
// Work with files up to 1 subdirectory deep
depth: 1
};

В основном вам нужно только предоставить корневое свойство, которое указывает, какой каталог будет исследован.

Модуль предлагает 2 способа использования, первый с обратными вызовами:

// Import the module
var readdirp = require('readdirp');
var settings = {
root: './your-folder-path',
entryType: 'all'
};
// In this example, this variable will store all the paths of the files and directories inside the providen path
var allFilePaths = [];
// Iterate recursively through a folder
readdirp(settings,
// This callback is executed everytime a file or directory is found inside the providen path
function(fileInfo) {
// Store the fullPath of the file/directory in our custom array
allFilePaths.push(
fileInfo.fullPath
);
},
// This callback is executed once
function (err, res) {
if(err){
throw err;
}
// An array with all the fileEntry objects of the folder
// console.log(res);
console.log(allFilePaths);
// ["c:/file.txt",""]
}
);

Или через потоковый API:

// Import the module
var readdirp = require('readdirp');
var settings = {
root: './',
entryType: 'all'
};
// In this example, this variable will store all the paths of the files and directories inside the providen path
var allFilePaths = [];
// Iterate recursively through a folder
readdirp(settings)
.on('data', function (entry) {
// execute everytime a file is found in the providen directory
// Store the fullPath of the file/directory in our custom array
allFilePaths.push(
entry.fullPath
);
})
.on('warn', function(warn){
console.log("Warn: ", warn);
})
.on('error', function(err){
console.log("Error: ", err);
})
.on('end', function(){
console.log(allFilePaths);
// ["c:/file.txt","c:/other-file.txt" ...]
})
;

каждый fileEntry Объект имеет следующую структуру, поэтому вы получите не только полный путь, но и более полезную информацию о файле или каталоге:

{
name: 'index.js',
path: 'node_modules\\string_decoder\\index.js',
fullPath: 'C:\\Users\\sdkca\\Desktop\\node-workspace\\node_modules\\string_decoder\\index.js',
parentDir: 'node_modules\\string_decoder',
fullParentDir: 'C:\\Users\\sdkca\\Desktop\\node-workspace\\node_modules\\string_decoder',
stat:
Stats {
dev: -469691281,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: undefined,
ino: 562949954035272,
size: 7796,
blocks: undefined,
atime: 2017 - 03 - 31T18: 27:30.703Z,
mtime: 2017 - 03 - 31T18: 27:30.724Z,
ctime: 2017 - 03 - 31T18: 27:30.724Z,
birthtime: 2017 - 03 - 31T18: 27:30.703Z
}
};

Для получения дополнительной информации, пожалуйста, посетите репозиторий модуля в Github здесь.

C. Использование модулей klaw и klaw-sync

Изначально многие разработчики полагались на модуль гаечного ключа (и многие до сих пор полагаются), однако сейчас это официально устарело, и мы любим продвигать стандарты, вам больше не следует его использовать (мы не запрещаем его, поэтому не стесняйтесь исследовать модуль, если хотите, но подумайте, что он устарел). В настоящее время проект рекомендует использовать модуль fs-extra, Однако модуль не поддерживает walk() а также walkSync() функции больше (причина, по которой разработчики использовали модуль гаечного ключа для рекурсивного исследования каталога).

Поскольку рекурсивные функции больше не доступны, модуль fs-extra рекомендует использовать модуль klaw. Этот модуль предоставляет асинхронный обходчик файловой системы Node.js с интерфейсом для чтения потоков, изначально извлеченным из модуля fs-extra.

Чтобы установить этот модуль, выполните следующую команду в своем терминале:

npm install klaw

Klaw очень прост в использовании и настраивается. Для рекурсивного цикла по каталогу используйте следующий фрагмент:

// Import the klaw module
var klaw = require('klaw');
// an array to store the folder and files inside
var items = [];
var directoryToExplore = "./some-folder";
klaw(directoryToExplore)
.on('data', function (item) {
items.push(item.path)
})
.on('end', function () {
console.log(items);
})
.on('error', function (err, item) {
console.log(err.message)
console.log(item.path) // the file the error occurred on
})
;

Поскольку он асинхронный, вам нужно полагаться на обратный вызов завершения, чтобы делать все, что вы хотите, со списком найденных файлов и каталогов в каталоге provn.

Для получения дополнительной информации об асинхронном модуле Klaw, пожалуйста, посетите официальный репозиторий в Github здесь.

Если вам нужна та же функциональность, но синхронная, вы можете использовать модуль klaw-sync. klaw-sync — это рекурсивный обходчик файловой системы Node.js, который является синхронным аналогом klaw. Он перечисляет все файлы и каталоги внутри каталога рекурсивно и возвращает массив объектов, каждый из которых имеет два свойства: path а также stats, путь — это полный путь к файлу или каталогу, а статистика — это экземпляр fs.Stats,

Чтобы установить этот модуль, выполните следующую команду в своем терминале:

npm install klaw-sync

Синхронная версия klaw так же проста в использовании, как и асинхронная версия, однако она более настраиваема, чем ее аналог. Вы можете использовать следующий фрагмент для просмотра каталога:

// Require the module
var klawSync = require('klaw-sync');
// Create an empty variable to be accesible in the closure
var paths;
// The directory that you want to explore
var directoryToExplore = "./folder-to-explore";
try {
paths = klawSync(directoryToExplore);
} catch (err) {
console.error(err);
}
// [
//   {path:"c:/file.txt", stats: {..File information..}},
//   {path:"c:/file.txt", stats: {..File information..}},
//   {path:"c:/file.txt", stats: {..File information..}},
// ]
console.log(paths);

klaw-sync позволяет фильтровать каталоги и файлы по расширению, имени. Кроме того, вы можете искать только каталоги или файлы по настройка параметров:

var klawSync = require('klaw-sync');
var directoryToExplore = "./some-folder";
var files = klawSync(directoryToExplore, {
nodir: true
});
// [
//   {path:"c:/file.txt", stats: {..File information..}},
//   {path:"c:/file2.txt", stats: {..File information..}},
//   {path:"c:/file3.txt", stats: {..File information..}},
// ]
console.log(files);
var paths = klawSync(directoryToExplore, {
nofile: true
});
// [
//   {path:"c:/folder", stats: {..Folder information..}},
//   {path:"c:/folder2", stats: {..Folder information..}},
//   {path:"c:/folder3", stats: {..Folder information..}},
// ]
console.log(paths);

Для получения дополнительной информации о синхронном модуле Klaw, пожалуйста, посетите официальный репозиторий в Github здесь.

Klaw означает «ходьба» (но в обратном направлении), и оказалось (по состоянию на 25 января 2017 года) в большинстве случаев, что klaw и klaw-sync работают быстрее, чем другие модули.

Ссылка на основную публикацию
Adblock
detector