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

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

Ответ 1

Вы можете использовать методы 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);
});

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

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

Ответ 2

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

npm install glob

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

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.
})

Ответ 3

В приведенном выше ответе не выполняется рекурсивный поиск в каталоге. Вот что я сделал для рекурсивного поиска (используя 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);
});

Ответ 4

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

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'))

Ответ 5

Здесь простое решение, использующее только собственные 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"...
});

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

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

Ответ 6

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

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

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

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));

Ответ 7

Зависимости.

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 слишком оптимистичен. Для чего-нибудь серьезного, добавьте некоторые ошибки обработки.

Ответ 8

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

Пример кода:

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

fs.readdirSync('your-directory-path')
  .filter((file) => fs.lstatSync(path.join(folder, file)).isFile());

Ответ 9

Начиная с 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

Ответ 10

Загрузить fs:

const fs = require('fs');

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

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

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

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

Ответ 11

Получить sorted имена файлов. Вы можете фильтровать результаты по определенному extension например, '.txt', '.jpg' и так далее.

import * as fs from 'fs';
import * as Path from 'path';

function getFilenames(path, extension) {
    return fs
        .readdirSync(path)
        .filter(
            item =>
                fs.statSync(Path.join(path, item)).isFile() &&
                (extension === undefined || Path.extname(item) === extension)
        )
        .sort();
}

Ответ 12

Здесь представлена ​​асинхронная рекурсивная версия.

    function ( path, callback){
     // the callback gets ( err, files) where files is an array of file names
     if( typeof callback !== 'function' ) return
     var
      result = []
      , files = [ path.replace( /\/\s*$/, '' ) ]
     function traverseFiles (){
      if( files.length ) {
       var name = files.shift()
       fs.stat(name, function( err, stats){
        if( err ){
         if( err.errno == 34 ) traverseFiles()
    // in case there broken symbolic links or a bad path
    // skip file instead of sending error
         else callback(err)
        }
        else if ( stats.isDirectory() ) fs.readdir( name, function( err, files2 ){
         if( err ) callback(err)
         else {
          files = files2
           .map( function( file ){ return name + '/' + file } )
           .concat( files )
          traverseFiles()
         }
        })
        else{
         result.push(name)
         traverseFiles()
        }
       })
      }
      else callback( null, result )
     }
     traverseFiles()
    }

Ответ 13

Взял общий подход @Хунань-Ростомян, сделал его более лаконичным и добавил аргумент excludeDirs. Было бы тривиально распространяться с помощью includeDirs, просто следуйте одному и тому же шаблону:

import * as fs from 'fs';
import * as path from 'path';

function fileList(dir, excludeDirs?) {
    return fs.readdirSync(dir).reduce(function (list, file) {
        const name = path.join(dir, file);
        if (fs.statSync(name).isDirectory()) {
            if (excludeDirs && excludeDirs.length) {
                excludeDirs = excludeDirs.map(d => path.normalize(d));
                const idx = name.indexOf(path.sep);
                const directory = name.slice(0, idx === -1 ? name.length : idx);
                if (excludeDirs.indexOf(directory) !== -1)
                    return list;
            }
            return list.concat(fileList(name, excludeDirs));
        }
        return list.concat([name]);
    }, []);
}

Пример использования:

console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));

Ответ 14

если кто-то все еще ищет это, я делаю это:

import fs from 'fs';
import path from 'path';

const getAllFiles = dir =>
    fs.readdirSync(dir).reduce((files, file) => {
        const name = path.join(dir, file);
        const isDirectory = fs.statSync(name).isDirectory();
        return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name];
    }, []);

Ответ 15

Вы также можете сделать это рекурсивно.

Для этого есть модуль NPM:

нпм дри

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

Вот код:

const dree = require('dree');

const fileNames = [];
const fileCb = function(file) {
    fileNames.push(file.name);
}

dree.scan('path-to-directory', { extensions: [ 'html', 'js' ] }, fileCb);

console.log(fileNames); // All the html and js files inside the given folder and its subfolders

Ответ 16

Просто голова: если вы планируете выполнять операции над каждым файлом в каталоге, попробуйте vinyl-fs (который используется gulp, система потоковой сборки).

Ответ 17

Я сделал модуль node для автоматизации этой задачи: mddir

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

node mddir "../relative/path/"

Для установки: npm install mddir -g

Чтобы создать уценку для текущего каталога: mddir

Сгенерировать для любого абсолютного пути: mddir/absolute/path

Сгенерировать для относительного пути: mddir ~/Documents/whatever.

Файл md создается в вашем рабочем каталоге.

В настоящее время игнорирует папки node_modules и .git.

Устранение неполадок

Если вы получили сообщение об ошибке "node\r: Нет такого файла или каталога", проблема заключается в том, что ваша операционная система использует разные концы строк, и mddir не может их разобрать без явной установки стиля окончания строки в Unix, Это обычно затрагивает Windows, но также некоторые версии Linux. Настройка конца строки в стиле Unix должна выполняться в глобальной папке bin mddir npm.

Исправления строк

Получить путь к папке npm bin с помощью:

npm config get prefix

Cd в эту папку

brew установить dos2unix

dos2unix lib/ node_modules/mddir/src/mddir.js

Это преобразует окончание строк в Unix вместо Dos

Затем выполните как обычно: node mddir "../relative/path/".

Пример сгенерированной файловой структуры markdown 'directoryList.md'

    |-- .bowerrc
    |-- .jshintrc
    |-- .jshintrc2
    |-- Gruntfile.js
    |-- README.md
    |-- bower.json
    |-- karma.conf.js
    |-- package.json
    |-- app
        |-- app.js
        |-- db.js
        |-- directoryList.md
        |-- index.html
        |-- mddir.js
        |-- routing.js
        |-- server.js
        |-- _api
            |-- api.groups.js
            |-- api.posts.js
            |-- api.users.js
            |-- api.widgets.js
        |-- _components
            |-- directives
                |-- directives.module.js
                |-- vendor
                    |-- directive.draganddrop.js
            |-- helpers
                |-- helpers.module.js
                |-- proprietary
                    |-- factory.actionDispatcher.js
            |-- services
                |-- services.cardTemplates.js
                |-- services.cards.js
                |-- services.groups.js
                |-- services.posts.js
                |-- services.users.js
                |-- services.widgets.js
        |-- _mocks
            |-- mocks.groups.js
            |-- mocks.posts.js
            |-- mocks.users.js
            |-- mocks.widgets.js

Ответ 18

Используйте модуль списка содержимого npm. Он читает содержимое и под-содержимое данного каталога и возвращает список путей к файлам и папкам.

const list = require('list-contents');

list("./dist",(o)=>{
  if(o.error) throw o.error;
   console.log('Folders: ', o.dirs);
   console.log('Files: ', o.files);
});

Ответ 19

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

Я использовал fs-extra, потому что это просто супер набор улучшений для fs.

import * as FsExtra from 'fs-extra'

/**
 * Finds files in the folder that match filePattern, optionally passing back errors .
 * If folderDepth isn't specified, only the first level is searched. Otherwise anything up
 * to Infinity is supported.
 *
 * @static
 * @param {string} folder The folder to start in.
 * @param {string} [filePattern='.*'] A regular expression of the files you want to find.
 * @param {(Error[] | undefined)} [errors=undefined]
 * @param {number} [folderDepth=0]
 * @returns {Promise<string[]>}
 * @memberof FileHelper
 */
public static async findFiles(
    folder: string,
    filePattern: string = '.*',
    errors: Error[] | undefined = undefined,
    folderDepth: number = 0
): Promise<string[]> {
    const results: string[] = []

    // Get all files from the folder
    let items = await FsExtra.readdir(folder).catch(error => {
        if (errors) {
            errors.push(error) // Save errors if we wish (e.g. folder perms issues)
        }

        return results
    })

    // Go through to the required depth and no further
    folderDepth = folderDepth - 1

    // Loop through the results, possibly recurse
    for (const item of items) {
        try {
            const fullPath = Path.join(folder, item)

            if (
                FsExtra.statSync(fullPath).isDirectory() &&
                folderDepth > -1)
            ) {
                // Its a folder, recursively get the child folders' files
                results.push(
                    ...(await FileHelper.findFiles(fullPath, filePattern, errors, folderDepth))
                )
            } else {
                // Filter by the file name pattern, if there is one
                if (filePattern === '.*' || item.search(new RegExp(filePattern, 'i')) > -1) {
                    results.push(fullPath)
                }
            }
        } catch (error) {
            if (errors) {
                errors.push(error) // Save errors if we wish
            }
        }
    }

    return results
}

Ответ 20

Это сработает и сохранит результат в файле test.txt, который будет находиться в том же каталоге

  fs.readdirSync(__dirname).forEach(file => {
    fs.appendFileSync("test.txt", file+"\n", function(err){
    })
})

Ответ 21

function getFilesRecursiveSync(dir, fileList, optionalFilterFunction) {
    if (!fileList) {
        grunt.log.error("Variable 'fileList' is undefined or NULL.");
        return;
    }
    var files = fs.readdirSync(dir);
    for (var i in files) {
        if (!files.hasOwnProperty(i)) continue;
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()) {
            getFilesRecursiveSync(name, fileList, optionalFilterFunction);
        } else {
            if (optionalFilterFunction && optionalFilterFunction(name) !== true)
                continue;
            fileList.push(name);
        }
    }
}