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?
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.
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);
});
À 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.
})
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'))
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.
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 ) }
};
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));
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.
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());
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');
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']));
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();
}
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
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
}
À 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']
Utilisez npm
list-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);
});
J'ai créé un module de nœud pour automatiser cette tâche: mddir
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.
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.
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/".
|-- .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
Vous pourriez aussi vouloir le faire récursivement.
Il existe un module NPM pour cela:
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
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){
})
})