web-dev-qa-db-fra.com

Obtenir tous les répertoires dans le répertoire nodejs

J'espérais que ce serait une chose simple, mais je ne trouve rien pour le faire.

Je veux juste obtenir tous les dossiers/répertoires d'un dossier/répertoire donné.

Donc par exemple:

<MyFolder>
|- SomeFolder
|- SomeOtherFolder
|- SomeFile.txt
|- SomeOtherFile.txt
|- x-directory

Je m'attendrais à obtenir un tableau de:

["SomeFolder", "SomeOtherFolder", "x-directory"]

Ou ce qui précède avec le chemin si c'était comme ça que ça a été servi ...

Alors, existe-t-il déjà quelque chose pour faire ce qui précède?

192
Grofit

Voici une version plus courte et synchrone de cette réponse qui peut lister tous les répertoires (cachés ou non) dans le répertoire actuel:

const { lstatSync, readdirSync } = require('fs')
const { join } = require('path')

const isDirectory = source => lstatSync(source).isDirectory()
const getDirectories = source =>
  readdirSync(source).map(name => join(source, name)).filter(isDirectory)
347
Nick McCurdy

Grâce à JavaScript ES6 (ES2015), la syntaxe est simple:

** Version synchrone **

const { readdirSync, statSync } = require('fs')
const { join } = require('path')

const dirs = p => readdirSync(p).filter(f => statSync(join(p, f)).isDirectory())

Version asynchrone pour Node.js 10+ (expérimental)

const { readdir, stat } = require("fs").promises
const { join } = require("path")

const dirs = async path => {
  let dirs = []
  for (const file of await readdir(path)) {
    if ((await stat(join(path, file))).isDirectory()) {
      dirs = [...dirs, file]
    }
  }
  return dirs
}
80
pravdomil

Liste des répertoires en utilisant un chemin.

function getDirectories(path) {
  return fs.readdirSync(path).filter(function (file) {
    return fs.statSync(path+'/'+file).isDirectory();
  });
}
21
Titlacauan

Solution récursive

Je suis venu ici à la recherche d'un moyen d'obtenir tous les sous-répertoires et tous leurs sous-répertoires, etc. En me basant sur le réponse acceptée , j'ai écrit ceci:

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

function flatten(lists) {
  return lists.reduce((a, b) => a.concat(b), []);
}

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath)
    .map(file => path.join(srcpath, file))
    .filter(path => fs.statSync(path).isDirectory());
}

function getDirectoriesRecursive(srcpath) {
  return [srcpath, ...flatten(getDirectories(srcpath).map(getDirectoriesRecursive))];
}
15
Patrick McElhaney

Cela devrait le faire:

CoffeeScript (sync)

fs = require 'fs'

getDirs = (rootDir) ->
    files = fs.readdirSync(rootDir)
    dirs = []

    for file in files
        if file[0] != '.'
            filePath = "#{rootDir}/#{file}"
            stat = fs.statSync(filePath)

            if stat.isDirectory()
                dirs.Push(file)

    return dirs

CoffeeScript (async)

fs = require 'fs'

getDirs = (rootDir, cb) ->
    fs.readdir rootDir, (err, files) ->
        dirs = []

        for file, index in files
            if file[0] != '.'
                filePath = "#{rootDir}/#{file}"
                fs.stat filePath, (err, stat) ->
                    if stat.isDirectory()
                        dirs.Push(file)
                    if files.length == (index + 1)
                        cb(dirs)

JavaScript (asynchrone)

var fs = require('fs');
var getDirs = function(rootDir, cb) { 
    fs.readdir(rootDir, function(err, files) { 
        var dirs = []; 
        for (var index = 0; index < files.length; ++index) { 
            var file = files[index]; 
            if (file[0] !== '.') { 
                var filePath = rootDir + '/' + file; 
                fs.stat(filePath, function(err, stat) {
                    if (stat.isDirectory()) { 
                        dirs.Push(this.file); 
                    } 
                    if (files.length === (this.index + 1)) { 
                        return cb(dirs); 
                    } 
                }.bind({index: index, file: file})); 
            }
        }
    });
}
9
nicksweet

Sinon, si vous pouvez utiliser des bibliothèques externes, vous pouvez utiliser filehound. Il prend en charge les rappels, les promesses et les appels de synchronisation. 

Utilisation des promesses:

const Filehound = require('filehound');

Filehound.create()
  .path("MyFolder")
  .directory() // only search for directories
  .find()
  .then((subdirectories) => {
    console.log(subdirectories);
  });

Utilisation des rappels:

const Filehound = require('filehound');

Filehound.create()
  .path("MyFolder")
  .directory()
  .find((err, subdirectories) => {
    if (err) return console.error(err);

    console.log(subdirectories);
  });

Appel de synchronisation:

const Filehound = require('filehound');

const subdirectories = Filehound.create()
  .path("MyFolder")
  .directory()
  .findSync();

console.log(subdirectories);

Pour plus d'informations (et exemples), consultez la documentation: https://github.com/nspragg/filehound

Disclaimer: je suis l'auteur.

5
nickool

Utilisation de fs-extra, qui promet les appels async fs, ainsi que la nouvelle syntaxe async wait: 

const fs = require("fs-extra");

async function getDirectories(path){
    let filesAndDirectories = await fs.readdir(path);

    let directories = [];
    await Promise.all(
        filesAndDirectories.map(name =>{
            return fs.stat(path + name)
            .then(stat =>{
                if(stat.isDirectory()) directories.Push(name)
            })
        })
    );
    return directories;
}

let directories = await getDirectories("/")
3
1mike12

Avec la version node.js> = v10.13.0, fs.readdirSync retournera un tableau de fs.Dirent objects si l’option withFileTypes est définie sur true.

Pour que vous puissiez utiliser,

const fs = require('fs')

const directories = source => fs.readdirSync(source, {
   withFileTypes: true
}).reduce((a, c) => {
   c.isDirectory() && a.Push(c.name)
   return a
}, [])
3
Mayur

Et pour une version async de getDirectories, vous avez besoin du module async pour cela:

var fs = require('fs');
var path = require('path');
var async = require('async'); // https://github.com/caolan/async

// Original function
function getDirsSync(srcpath) {
  return fs.readdirSync(srcpath).filter(function(file) {
    return fs.statSync(path.join(srcpath, file)).isDirectory();
  });
}

function getDirs(srcpath, cb) {
  fs.readdir(srcpath, function (err, files) {
    if(err) { 
      console.error(err);
      return cb([]);
    }
    var iterator = function (file, cb)  {
      fs.stat(path.join(srcpath, file), function (err, stats) {
        if(err) { 
          console.error(err);
          return cb(false);
        }
        cb(stats.isDirectory());
      })
    }
    async.filter(files, iterator, cb);
  });
}
3
JumpLink
 var getDirectories = (rootdir , cb) => {
    fs.readdir(rootdir, (err, files) => {
        if(err) throw err ;
        var dirs = files.map(filename => path.join(rootdir,filename)).filter( pathname => fs.statSync(pathname).isDirectory());
        return cb(dirs);
    })

 }
 getDirectories( myDirectories => console.log(myDirectories));``
2
Jonathan bonzali

Cette réponse n'utilise pas de fonctions de blocage telles que readdirSync ou statSync. Il n'utilise pas de dépendances externes et ne se trouve pas dans les profondeurs de l'enfer de rappel.

Au lieu de cela, nous utilisons des fonctionnalités JavaScript modernes telles que les syntaxes Promises et async-await. Et les résultats asynchrones sont traités en parallèle; pas séquentiellement -

const { readdir, stat } =
  require ("fs") .promises

const { join } =
  require ("path")

const dirs = async (path = ".") =>
  (await stat (path)) .isDirectory ()
    ? Promise
        .all
          ( (await readdir (path))
              .map (p => dirs (join (path, p)))
          )
        .then
          ( results =>
              [] .concat (path, ...results)
          )
    : []

Je vais installer un exemple de paquet, puis tester notre fonction -

$ npm install ramda
$ node

Voyons voir que ça marche -

> dirs (".") .then (console.log, console.error)

[ '.'
, 'node_modules'
, 'node_modules/ramda'
, 'node_modules/ramda/dist'
, 'node_modules/ramda/es'
, 'node_modules/ramda/es/internal'
, 'node_modules/ramda/src'
, 'node_modules/ramda/src/internal'
]

En utilisant un module généralisé, Parallel, nous pouvons simplifier la définition de dirs -

const Parallel =
  require ("./Parallel")

const dirs = async (path = ".") =>
  (await stat (path)) .isDirectory ()
    ? Parallel (readdir (path))
        .flatMap (f => dirs (join (path, f)))
        .then (results => [ path, ...results ])
    : []

Le module Parallel utilisé ci-dessus était un modèle extrait d'un ensemble de fonctions conçues pour résoudre un problème similaire. Pour plus d'explications, voir ceci Questions/Réponses liées .

1
user633183

Si vous devez utiliser toutes les versions async. Vous pouvez avoir quelque chose comme ça.

  1. Enregistrez la longueur du répertoire et l'utilisez comme indicateur pour indiquer si toutes les tâches de statistiques asynchrones sont terminées.

  2. Si les tâches de statistiques asynchrones sont terminées, toutes les statistiques de fichier ont été vérifiées. Appelez le rappel.

Cela ne fonctionnera que tant que Node.js sera un seul thread, car cela suppose qu'aucune tâche asynchrone n'augmentera le compteur en même temps.

'use strict';

var fs = require("fs");
var path = require("path");
var basePath = "./";

function result_callback(results) {
    results.forEach((obj) => {
        console.log("isFile: " + obj.fileName);
        console.log("fileName: " + obj.isFile);
    });
};

fs.readdir(basePath, (err, files) => {
    var results = [];
    var total = files.length;
    var finished = 0;

    files.forEach((fileName) => {
        // console.log(fileName);
        var fullPath = path.join(basePath, fileName);

        fs.stat(fullPath, (err, stat) => {
            // this will work because Node.js is single thread
            // therefore, the counter will not increment at the same time by two callback
            finished++;

            if (stat.isFile()) {
                results.Push({
                    fileName: fileName,
                    isFile: stat.isFile()
                });
            }

            if (finished == total) {
                result_callback(results);
            }
        });
    });
});

Comme vous pouvez le constater, il s’agit d’une approche de «profondeur d’abord» qui pourrait entraîner un rappel instable et qui n’est pas tout à fait «fonctionnelle». Les gens essaient de résoudre ce problème avec Promise en encapsulant la tâche async dans un objet Promise.

'use strict';

var fs = require("fs");
var path = require("path");
var basePath = "./";

function result_callback(results) {
    results.forEach((obj) => {
        console.log("isFile: " + obj.fileName);
        console.log("fileName: " + obj.isFile);
    });
};

fs.readdir(basePath, (err, files) => {
    var results = [];
    var total = files.length;
    var finished = 0;

    var promises = files.map((fileName) => {
        // console.log(fileName);
        var fullPath = path.join(basePath, fileName);

        return new Promise((resolve, reject) => {
            // try to replace fullPath wil "aaa", it will reject
            fs.stat(fullPath, (err, stat) => {
                if (err) {
                    reject(err);
                    return;
                }

                var obj = {
                    fileName: fileName,
                    isFile: stat.isFile()
                };

                resolve(obj);
            });
        });
    });

    Promise.all(promises).then((values) => {
        console.log("All the promise resolved");
        console.log(values);
        console.log("Filter out folder: ");
        values
            .filter((obj) => obj.isFile)
            .forEach((obj) => {
                console.log(obj.fileName);
            });
    }, (reason) => {
        console.log("Not all the promise resolved");
        console.log(reason);
    });
});
1
code4j

utiliser fs 、 chemin module peut obtenir le dossier. cette promesse d'utilisation. Si vous voulez obtenir le remplissage, vous pouvez changer isDirectory () en isFile ()Nodejs - fs - fs.Stats . Enfin, vous pouvez obtenir le fichier nom_fichier 'extname et ainsi de suite Nodejs --- Path

var fs = require("fs"),
path = require("path");
//your <MyFolder> path
var p = "MyFolder"
fs.readdir(p, function (err, files) {
    if (err) {
        throw err;
    }
    //this can get all folder and file under  <MyFolder>
    files.map(function (file) {
        //return file or folder path, such as **MyFolder/SomeFile.txt**
        return path.join(p, file);
    }).filter(function (file) {
        //use sync judge method. The file will add next files array if the file is directory, or not. 
        return fs.statSync(file).isDirectory();
    }).forEach(function (files) {
        //The files is array, so each. files is the folder name. can handle the folder.
        console.log("%s", files);
    });
});
1
Howard

Version CoffeeScript de cette réponse , avec une gestion des erreurs appropriée:

fs = require "fs"
{join} = require "path"
async = require "async"

get_subdirs = (root, callback)->
    fs.readdir root, (err, files)->
        return callback err if err
        subdirs = []
        async.each files,
            (file, callback)->
                fs.stat join(root, file), (err, stats)->
                    return callback err if err
                    subdirs.Push file if stats.isDirectory()
                    callback null
            (err)->
                return callback err if err
                callback null, subdirs

Dépend de asynchrone

Sinon, utilisez un module pour cela! (Il existe des modules pour tout. [Citation nécessaire])

1
1j01

Version entièrement async avec ES6, seuls les packages natifs, fs.promises et async/wait, effectuent des opérations de fichier en parallèle:

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

async function listDirectories(rootPath) {
    const fileNames = await fs.promises.readdir(rootPath);
    const filePaths = fileNames.map(fileName => path.join(rootPath, fileName));
    const filePathsAndIsDirectoryFlagsPromises = filePaths.map(async filePath => ({path: filePath, isDirectory: (await fs.promises.stat(filePath)).isDirectory()}))
    const filePathsAndIsDirectoryFlags = await Promise.all(filePathsAndIsDirectoryFlagsPromises);
    return filePathsAndIsDirectoryFlags.filter(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.isDirectory)
        .map(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.path);
}

Testé, ça marche bien.

0

Une autre approche récursive

Merci à Mayur de me connaître à propos de withFileTypes. J'ai écrit le code suivant pour obtenir des fichiers d'un dossier particulier de manière récursive. Il peut être facilement modifié pour obtenir uniquement des répertoires.

const getFiles = (dir, base = '') => readdirSync(dir, {withFileTypes: true}).reduce((files, file) => {
    const filePath = path.join(dir, file.name)
    const relativePath = path.join(base, file.name)
    if(file.isDirectory()) {
        return files.concat(getFiles(filePath, relativePath))
    } else if(file.isFile()) {
        file.__fullPath = filePath
        file.__relateivePath = relativePath
        return files.concat(file)
    }
}, [])
0

Juste au cas où quelqu'un d'autre finirait ici par une recherche sur le Web et que Grunt soit déjà dans sa liste de dépendances, la réponse à cette question devient triviale. Voici ma solution:

/**
 * Return all the subfolders of this path
 * @param {String} parentFolderPath - valid folder path
 * @param {String} glob ['/*'] - optional glob so you can do recursive if you want
 * @returns {String[]} subfolder paths
 */
getSubfolders = (parentFolderPath, glob = '/*') => {
    return grunt.file.expand({filter: 'isDirectory'}, parentFolderPath + glob);
}
0
Artif3x

Personnellement, je déclarerais la fonction stat hors de la boucle - quelque chose comme ceci:

function getSubDirs(dir, cb) {
    fs.readdir(dir, function(err, files) {
        var dirs = [],
        filePath,
        checkDirectory = function(err, stat) {
            if(stat.isDirectory()) {
                dirs.Push(files[i]);
            }
            if(i + 1 === l) { // last record
                cb(dirs);
            }
        };

        for(var i=0, l=files.length; i<l; i++) {
            if(files[i][0] !== '.') { // ignore hidden
                filePath = dir+'/'+files[i];
                fs.stat(filePath, checkDirectory);
            }
        }
    });
}

JShint se plaint sinon et vous créez peut-être un nouvel appel de fonction à chaque passage de boucle.

0
derekdreery

Async/attend la variante:

async function getFolders(path) {
    let result = Array();
    let files = await fs.readdir(path);
    for (let i = 0; i < files.length; i++) {
        var filePath = path + '/' + file;
        if (await fs.stat(filePath).isDirectory()) {
            result.Push(filePath);
        }
    }

    return result;
}

Je recommande également d’utiliser fs-extra au lieu de fs ..

0
jabko87

programmation fonctionnelle

const fs = require('fs')
const path = require('path')
const R = require('ramda')

const getDirectories = pathName => {
    const isDirectory = pathName => fs.lstatSync(pathName).isDirectory()
    const mapDirectories = pathName => R.map(name => path.join(pathName, name), fs.readdirSync(pathName))
    const filterDirectories = listPaths => R.filter(isDirectory, listPaths)

    return {
        paths:R.pipe(mapDirectories)(pathName),
        pathsFiltered: R.pipe(mapDirectories, filterDirectories)(pathName)
    }
}
0
Roy Alcala