Как получить список имен всех файлов, присутствующих в каталоге в Node.js? - PullRequest
794 голосов
/ 28 апреля 2010

Я пытаюсь получить список имен всех файлов, присутствующих в каталоге, используя Node.js. Я хочу вывод, который является массивом имен файлов. Как я могу это сделать?

Ответы [ 20 ]

1093 голосов
/ 28 апреля 2010

Вы можете использовать методы fs.readdir или fs.readdirSync.

fs.readdir

const testFolder = './tests/';
const fs = require('fs');

fs.readdir(testFolder, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});

fs.readdirSync

const testFolder = './tests/';
const fs = require('fs');

fs.readdirSync(testFolder).forEach(file => {
  console.log(file);
});

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

Второй является синхронным, он вернет массив имен файлов, но остановит дальнейшее выполнение вашего кода до завершения процесса чтения.

176 голосов
/ 30 августа 2014

IMO самый удобный способ выполнить такие задачи - использовать инструмент glob . Вот пакет glob для node.js. Установить с

npm install glob

Затем используйте шаблон для сопоставления имен файлов (пример взят с сайта пакета)

var glob = require("glob")

// options is optional
glob("**/*.js", options, function (er, files) {
  // files is an array of filenames.
  // If the `nonull` option is set, and nothing
  // was found, then files is ["**/*.js"]
  // er is an error object or null.
})
175 голосов
/ 27 апреля 2011

Ответ выше не выполняет рекурсивный поиск в каталоге. Вот что я сделал для рекурсивного поиска (используя node-walk : npm install walk)

var walk    = require('walk');
var files   = [];

// Walker options
var walker  = walk.walk('./test', { followLinks: false });

walker.on('file', function(root, stat, next) {
    // Add this file to the list of files
    files.push(root + '/' + stat.name);
    next();
});

walker.on('end', function() {
    console.log(files);
});
81 голосов
/ 11 декабря 2013

Получить файлы во всех подкаталогах

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}

console.log(getFiles('path/to/dir'))
56 голосов
/ 03 февраля 2015

Вот простое решение с использованием только собственных модулей fs и path:

// sync version
function walkSync(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdirSync(currentDirPath).forEach(function (name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walkSync(filePath, callback);
        }
    });
}

или асинхронная версия (вместо нее используется fs.readdir):

// async version with basic error handling
function walk(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdir(currentDirPath, function (err, files) {
        if (err) {
            throw new Error(err);
        }
        files.forEach(function (name) {
            var filePath = path.join(currentDirPath, name);
            var stat = fs.statSync(filePath);
            if (stat.isFile()) {
                callback(filePath, stat);
            } else if (stat.isDirectory()) {
                walk(filePath, callback);
            }
        });
    });
}

Тогда вы просто звоните (для синхронизации):

walkSync('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

или асинхронная версия:

walk('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

Разница заключается в том, как блокируются узлы при выполнении ввода-вывода. Учитывая, что приведенный выше API-интерфейс одинаков, вы можете просто использовать асинхронную версию для обеспечения максимальной производительности.

Однако есть одно преимущество использования синхронной версии. Некоторый код легче выполнить, как только завершится обход, как в следующем операторе после обхода. В асинхронной версии вам понадобится дополнительный способ узнать, когда вы закончите. Возможно, сначала создайте карту всех путей, а затем перечислите их. Для простых сценариев сборки / утилит (против высокопроизводительных веб-серверов) вы можете использовать синхронизирующую версию без каких-либо повреждений.

23 голосов
/ 30 мая 2016

Использование Promises с ES7

Асинхронное использование с mz / fs

Модуль mz предоставляет многообещающие версии библиотеки базовых узлов. Использовать их просто. Сначала установите библиотеку ...

npm install mz

Тогда ...

const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
  .catch(err => console.error(err));

В качестве альтернативы вы можете написать их в асинхронных функциях в ES7:

async function myReaddir () {
  try {
    const file = await fs.readdir('./myDir/');
  }
  catch (err) { console.error( err ) }
};

Обновление для рекурсивного листинга

Некоторые пользователи указали желание увидеть рекурсивный список (хотя и не в вопросе) ... Используйте fs-promise Это тонкая оболочка вокруг mz.

npm install fs-promise;

тогда ...

const fs = require('fs-promise');
fs.walk('./myDir').then(
    listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
15 голосов
/ 13 ноября 2015

зависимостями.

var fs = require('fs');
var path = require('path');

Определение.

// String -> [String]
function fileList(dir) {
  return fs.readdirSync(dir).reduce(function(list, file) {
    var name = path.join(dir, file);
    var isDir = fs.statSync(name).isDirectory();
    return list.concat(isDir ? fileList(name) : [name]);
  }, []);
}

Usage.

var DIR = '/usr/local/bin';

// 1. List all files in DIR
fileList(DIR);
// => ['/usr/local/bin/babel', '/usr/local/bin/bower', ...]

// 2. List all file names in DIR
fileList(DIR).map((file) => file.split(path.sep).slice(-1)[0]);
// => ['babel', 'bower', ...]

Обратите внимание, что fileList слишком оптимистично. Для чего-то серьезного, добавьте обработку ошибок.

10 голосов
/ 01 июля 2016

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

Пример кода:

const fs = require('fs');
const path = require('path');

fs.readdirSync('your-directory-path')
  .filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
7 голосов
/ 30 января 2019

Начиная с Node v10.10.0, можно использовать новую опцию withFileTypes для fs.readdir и fs.readdirSync в сочетании с функцией dirent.isDirectory() для фильтрации имен файлов в каталоге. Это выглядит так:

fs.readdirSync('./dirpath', {withFileTypes: true})
.filter(item => !item.isDirectory())
.map(item => item.name)

Возвращенный массив имеет вид:

['file1.txt', 'file2.txt', 'file3.txt']

Документы для класса fs.Dirent

7 голосов
/ 13 сентября 2016

Загрузка fs:

const fs = require('fs');

Чтение файлов async :

fs.readdir('./dir', function (err, files) {
    // "files" is an Array with files names
});

Чтение файлов синхронизация :

var files = fs.readdirSync('./dir');
...