web-dev-qa-db-fra.com

Comment obtenez-vous une liste des noms de tous les fichiers présents dans un répertoire de Node.js?

J'essaie d'obtenir une liste des noms de tous les fichiers présents dans un répertoire à l'aide de Node.js. Je veux une sortie qui est un tableau de noms de fichiers. Comment puis-je faire ceci?

726
resopollution

Vous pouvez utiliser les méthodes fs.readdir ou 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);
});

La différence entre les deux méthodes est que la première est asynchrone. Vous devez donc fournir une fonction de rappel à exécuter à la fin du processus de lecture.

La seconde est synchrone, elle retournera le tableau de noms de fichiers, mais arrêtera toute exécution ultérieure de votre code jusqu'à la fin du processus de lecture.

988
CMS

La réponse ci-dessus n'effectue cependant pas une recherche récursive dans le répertoire. Voici ce que j'ai fait pour une recherche récursive (en utilisant 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);
});
172
Ruben Tan

À l’OMI, le moyen le plus pratique de faire de telles tâches est d’utiliser un outil glob Voici un paquet glob pour node.js. Installer avec

npm install glob

Utilisez ensuite un caractère générique pour faire correspondre les noms de fichiers (exemple tiré du site Web du paquet)

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

Obtenir des fichiers dans tous les sous-répertoires

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

Voici une solution simple utilisant uniquement les modules natifs fs et 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);
        }
    });
}

ou version async (utilise plutôt 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);
            }
        });
    });
}

Ensuite, vous appelez simplement (pour la version synchronisée):

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

ou version asynchrone:

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

La différence réside dans la façon dont le nœud se bloque lors de l'exécution de l'IO. Étant donné que l'API ci-dessus est la même, vous pouvez simplement utiliser la version asynchrone pour garantir des performances optimales.

Cependant, l'utilisation de la version synchrone présente un avantage. Il est plus facile d'exécuter du code dès que la marche est terminée, comme dans l'instruction suivante après la marche. Avec la version async, vous auriez besoin d'un moyen supplémentaire de savoir quand vous avez terminé. Peut-être créer d’abord une carte de tous les chemins, puis les énumérer. Pour les scripts simples de construction/utilisation (par rapport aux serveurs Web hautes performances), vous pouvez utiliser la version de synchronisation sans causer de dommages.

55
Ali

Utilisation de promesses avec ES7

Utilisation asynchrone avec mz/fs

Le module mz fournit des versions promisifiées de la bibliothèque de noeuds principaux. Les utiliser est simple. Installez d'abord la bibliothèque ...

npm install mz

Ensuite...

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

Vous pouvez également les écrire dans des fonctions asynchrones dans ES7:

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

Mise à jour pour une liste récursive

Certains utilisateurs ont indiqué qu'ils souhaitaient voir une liste récursive (mais pas dans la question) ... Utilisez fs-promise . C'est une mince enveloppe autour de mz .

npm install fs-promise;

puis...

const fs = require('fs-promise');
fs.walk('./myDir').then(
    listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
22
Evan Carroll

Dépendances.

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

Définition.

// 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]);
  }, []);
}

Utilisation.

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', ...]

Veuillez noter que fileList est trop optimiste. Pour quelque chose de grave, ajoutez un peu de gestion des erreurs.

15
Hunan Rostomyan

Vous ne dites pas que vous voulez le faire récursivement, alors je suppose que vous n'avez besoin que des enfants directs du répertoire.

Exemple de code:

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

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

Charger fs:

const fs = require('fs');

Lire les fichiers async:

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

Lire les fichiers sync:

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

Voici une version récursive asynchrone.

    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's 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()
    }

A adopté l'approche générale de @ Hunan-Rostomyan, en a fait un peu plus concis et en ajoutant excludeDirs Il serait trivial d'étendre avec includeDirs, il suffit de suivre le même schéma:

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]);
    }, []);
}

Exemple d'utilisation:

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

Obtenez les noms de fichiers sorted. Vous pouvez filtrer les résultats en fonction d'une extension spécifique, telle que '.txt', '.jpg', etc.

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();
}
3
Yas

si quelqu'un cherche toujours cela, je le fais:

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];
    }, []);

et son travail est très bien pour moi

1
Josh

Ceci est un TypeScript, éventuellement récursif, éventuellement une journalisation des erreurs et une solution asynchrone. Vous pouvez spécifier une expression régulière pour les noms de fichiers que vous souhaitez rechercher.

J'ai utilisé fs-extra, parce que c'est une amélioration facile et super améliorée de 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
}
0
Paul F. Wood

À partir du nœud 10.10.0, il est possible d'utiliser la nouvelle option withFileTypes pour fs.readdir et fs.readdirSync en combinaison avec la fonction dirent.isDirectory() pour filtrer les noms de fichiers dans un répertoire. Cela ressemble à ceci:

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

Le tableau retourné est sous la forme:

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

Docs pour la classe fs.Dirent

0
bnp887

Utilisez npmlist-contents module. Il lit le contenu et les sous-contenus du répertoire donné et renvoie la liste des chemins des fichiers et des dossiers.

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

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

J'ai créé un module de nœud pour automatiser cette tâche: mddir

Usage

noeud mddir "../relative/path/"

Pour installer: npm install mddir -g

Pour générer un démarquage pour le répertoire en cours: mddir

Pour générer un chemin absolu quelconque: mddir/absolute/path

Pour générer un chemin relatif: mddir ~/Documents/what.

Le fichier md est généré dans votre répertoire de travail.

Ignore actuellement les dossiers node_modules et .git.

Dépannage

Si vous recevez l'erreur 'noeud\r: Aucun fichier ou répertoire de ce type', le problème est que votre système d'exploitation utilise différentes fins de ligne et que mddir ne peut pas les analyser sans que vous ayez défini explicitement le style de fin de ligne sur Unix. Cela affecte généralement Windows, mais aussi certaines versions de Linux. La définition des fins de ligne sur le style Unix doit être effectuée dans le dossier bin global de mddir npm.

Correction des fins de ligne

Obtenez le chemin du dossier bin npm avec:

npm config get prefix

Cd dans ce dossier

brasser installer dos2unix

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

Ceci convertit les fins de ligne en Unix au lieu de Dos

Exécutez ensuite normalement avec: node mddir "../relative/path/".

Exemple de structure de fichier de démarquage générée '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
0
John Byrne

Vous pourriez aussi vouloir le faire récursivement.

Il existe un module NPM pour cela: 

npm dree

Il vous permet d'avoir une représentation d'une arborescence de répertoires sous forme de chaîne ou d'objet. Avec le rappel de fichier, vous pouvez également atteindre votre objectif. Si vous le souhaitez, vous pouvez également spécifier les extensions de fichier à prendre en compte. 

Voici le code:

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
0
EuberDeveloper

Juste un avertissement: si vous prévoyez d'effectuer des opérations sur chaque fichier d'un répertoire, essayez vinyl-fs (qui est utilisé par gulp , le système de génération en continu).

0

Cela fonctionnera et stockera le résultat dans le fichier test.txt qui sera présent dans le même répertoire

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