nœud.js fs.readdir récursive recherche dans l'annuaire
toutes les idées sur une recherche de répertoire async en utilisant fs.readdir? Je me rends compte que nous pourrions introduire la récursion et appeler la fonction read directory avec le prochain répertoire à lire, mais je suis un peu inquiet que ce ne soit pas async...
des idées? J'ai regardé nœud-pied qui est excellent, mais ne me donne pas seulement les fichiers dans un tableau, comme readdir. Bien que
recherche de sortie comme...
['file1.txt', 'file2.txt', 'dir/file3.txt']
30 réponses
il y a essentiellement deux façons d'accomplir ceci. Dans un environnement asynchrone, vous remarquerez qu'il y a deux types de boucles: série et parallèle. Une boucle en série attend qu'une itération se termine avant de passer à la prochaine itération - ce qui garantit que chaque itération de la boucle se termine dans l'ordre. Dans une boucle parallèle, toutes les itérations sont lancées en même temps, et l'une peut se terminer avant l'autre, cependant, elle est beaucoup plus rapide qu'une boucle série. Donc, dans ce cas, il est il est probablement préférable d'utiliser une boucle parallèle, car peu importe l'ordre dans lequel la marche se déroule, tant qu'elle se termine et renvoie les résultats (à moins que vous ne les vouliez dans l'ordre).
une boucle parallèle ressemblerait à ceci:
var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
une boucle série ressemblerait à ceci:
var fs = require('fs');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
};
Et de le tester sur votre répertoire home (AVERTISSEMENT: la liste des résultats sera énorme si vous avez beaucoup de choses dans votre maison répertoire):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
modifier: exemples améliorés.
A. regardez le file module . Il a une fonction appelée walk:
"151930920 de fichier".walk (start, callback)
navigue dans une arborescence de fichiers, appelant la fonction de rappel pour chaque répertoire, passant par (null, dirPath, dirs, les fichiers).
C'est peut-être pour vous! Et oui, il est asynchrone. Cependant, je pense que vous devriez agréger les chemin d'accès complet de vous-même, si vous avez besoin d'eux.
B. une alternative, et même l'un de mes favoris: Utilisez le unix find
pour cela. Pourquoi recommencer quelque chose qui a déjà été programmé? Peut-être pas exactement ce dont vous avez besoin, mais ça vaut quand même le coup de vérifier:
var execFile = require('child_process').execFile;
execFile('find', [ 'somepath/' ], function(err, stdout, stderr) {
var file_list = stdout.split('\n');
/* now you've got a list with full path file names */
});
Find a un mécanisme de cache intégré qui rend les recherches ultérieures très rapides, aussi longtemps que peu de dossiers ont changé.
juste au cas où quelqu'un le trouve utile, j'ai aussi mis en place une version synchrone .
var walk = function(dir) {
var results = [];
var list = fs.readdirSync(dir);
list.forEach(function(file) {
file = dir + '/' + file;
var stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
/* Recurse into a subdirectory */
results = results.concat(walk(file));
} else {
/* Is a file */
results.push(file);
}
});
return results;
}
Conseil: utiliser moins de ressources lors du filtrage. Filtrer dans cette fonction elle-même. Par exemple: Remplacer results.push(file);
par le code ci-dessous. Ajuster au besoin:
file_type = file.split(".").pop();
file_name = file.split(/(\|\/)/g).pop();
if (file_type == "json") results.push(file);
un autre joli paquet npm est glob .
npm install glob
il est très puissant et devrait couvrir tous vos besoins récurrents.
Edit:
en fait, je n'étais pas parfaitement heureux avec glob, donc j'ai créé readdirp .
je suis très confiant que son API rend la recherche de fichiers et de répertoires récursivement et l'application de filtres spécifiques très facile.
lire à travers sa documentation pour obtenir une meilleure idée de ce qu'il fait et installer via:
npm install readdirp
je recommande d'utiliser node-glob pour accomplir cette tâche.
var glob = require( 'glob' );
glob( 'dirname/**/*.js', function( err, files ) {
console.log( files );
});
celui-ci utilise la quantité maximale de nouvelles fonctionnalités buzzwordy disponibles dans le noeud 8, y compris les promesses, util/promisify, la déstructuration, async-wait, map+reduce et plus encore, ce qui fait que vos collègues se grattent la tête alors qu'ils essaient de comprendre ce qui se passe.
pas de dépendances externes (noeud 8+).
const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
async function getFiles(dir) {
const subdirs = await readdir(dir);
const files = await Promise.all(subdirs.map(async (subdir) => {
const res = resolve(dir, subdir);
return (await stat(res)).isDirectory() ? getFiles(res) : res;
}));
return files.reduce((a, f) => a.concat(f), []);
}
Utilisation:
getFiles(__dirname)
.then(files => console.log(files))
.catch(e => console.error(e));
si vous voulez utiliser un paquet npm, clé est assez bon.
var wrench = require("wrench");
var files = wrench.readdirSyncRecursive("directory");
wrench.readdirRecursive("directory", function (error, files) {
// live your dreams
});
EDIT (2018):
toute personne lisant ces derniers temps: l'auteur a déprécié ce paquet en 2015:
clé à molette.js est obsolète, et n'a pas été mis à jour depuis un certain temps. je recommande fortement d'utiliser fs-extra pour faire n'importe quel système de fichiers supplémentaire opérations.
j'ai adoré la réponse à partir de chjj ci-dessus et n'aurait pas été en mesure de créer ma version de la boucle parallèle sans que commencer.
var fs = require("fs");
var tree = function(dir, done) {
var results = {
"path": dir
,"children": []
};
fs.readdir(dir, function(err, list) {
if (err) { return done(err); }
var pending = list.length;
if (!pending) { return done(null, results); }
list.forEach(function(file) {
fs.stat(dir + '/' + file, function(err, stat) {
if (stat && stat.isDirectory()) {
tree(dir + '/' + file, function(err, res) {
results.children.push(res);
if (!--pending){ done(null, results); }
});
} else {
results.children.push({"path": dir + "/" + file});
if (!--pending) { done(null, results); }
}
});
});
});
};
module.exports = tree;
j'ai créé l'Essentiel . Commentaires bienvenus. Je commence toujours dans le royaume de NodeJS donc c'est une façon que j'espère apprendre plus.
utiliser node-dir pour produire exactement la sortie que vous aimez
var dir = require('node-dir');
dir.files(__dirname, function(err, files) {
if (err) throw err;
console.log(files);
//we have an array of files now, so now we can iterate that array
files.forEach(function(path) {
action(null, path);
})
});
Avec Récursion
var fs = require('fs')
var path = process.cwd()
var files = []
var getFiles = function(path, files){
fs.readdirSync(path).forEach(function(file){
var subpath = path + '/' + file;
if(fs.lstatSync(subpath).isDirectory()){
getFiles(subpath, files);
} else {
files.push(path + '/' + file);
}
});
}
appel
getFiles(path, files)
console.log(files) // will log all files in directory
j'ai codé ceci récemment, et j'ai pensé qu'il serait logique de partager ceci ici. Le code utilise la bibliothèque async .
var fs = require('fs');
var async = require('async');
var scan = function(dir, suffix, callback) {
fs.readdir(dir, function(err, files) {
var returnFiles = [];
async.each(files, function(file, next) {
var filePath = dir + '/' + file;
fs.stat(filePath, function(err, stat) {
if (err) {
return next(err);
}
if (stat.isDirectory()) {
scan(filePath, suffix, function(err, results) {
if (err) {
return next(err);
}
returnFiles = returnFiles.concat(results);
next();
})
}
else if (stat.isFile()) {
if (file.indexOf(suffix, file.length - suffix.length) !== -1) {
returnFiles.push(filePath);
}
next();
}
});
}, function(err) {
callback(err, returnFiles);
});
});
};
Vous pouvez l'utiliser comme ceci:
scan('/some/dir', '.ext', function(err, files) {
// Do something with files that ends in '.ext'.
console.log(files);
});
découvrez les final-fs de la bibliothèque. Il fournit une fonction readdirRecursive
:
ffs.readdirRecursive(dirPath, true, 'my/initial/path')
.then(function (files) {
// in the `files` variable you've got all the files
})
.otherwise(function (err) {
// something went wrong
});
une bibliothèque appelée Filehound est une autre option. Il effectue une recherche récursive dans un répertoire donné (répertoire de travail par défaut). Il supporte divers filtres, callbacks, promesses et recherches de synchronisation.
par exemple, rechercher dans le répertoire de travail courant tous les fichiers (en utilisant des callbacks):
const Filehound = require('filehound');
Filehound.create()
.find((err, files) => {
if (err) {
return console.error(`error: ${err}`);
}
console.log(files); // array of files
});
ou promet et spécifie un répertoire spécifique:
const Filehound = require('filehound');
Filehound.create()
.paths("/tmp")
.find()
.each(console.log);
consulter les docs pour autres cas d'utilisation et exemples d'utilisation: https://github.com/nspragg/filehound
Avertissement: je suis l'auteur.
en utilisant async / wait, cela devrait fonctionner:
const FS = require('fs');
const readDir = promisify(FS.readdir);
const fileStat = promisify(FS.stat);
async function getFiles(dir) {
let files = await readDir(dir);
let result = files.map(file => {
let path = Path.join(dir,file);
return fileStat(path).then(stat => stat.isDirectory() ? getFiles(path) : path);
});
return flatten(await Promise.all(result));
}
function flatten(arr) {
return Array.prototype.concat(...arr);
}
vous pouvez utiliser oiseau bleu.Promisify ou:
/**
* Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
*
* @param {Function} nodeFunction
* @returns {Function}
*/
module.exports = function promisify(nodeFunction) {
return function(...args) {
return new Promise((resolve, reject) => {
nodeFunction.call(this, ...args, (err, data) => {
if(err) {
reject(err);
} else {
resolve(data);
}
})
});
};
};
Autonome promesse de la mise en œuvre
j'utilise le quand.js la promesse de la bibliothèque dans cet exemple.
var fs = require('fs')
, path = require('path')
, when = require('when')
, nodefn = require('when/node/function');
function walk (directory, includeDir) {
var results = [];
return when.map(nodefn.call(fs.readdir, directory), function(file) {
file = path.join(directory, file);
return nodefn.call(fs.stat, file).then(function(stat) {
if (stat.isFile()) { return results.push(file); }
if (includeDir) { results.push(file + path.sep); }
return walk(file, includeDir).then(function(filesInDir) {
results = results.concat(filesInDir);
});
});
}).then(function() {
return results;
});
};
walk(__dirname).then(function(files) {
console.log(files);
}).otherwise(function(error) {
console.error(error.stack || error);
});
j'ai inclus un paramètre optionnel includeDir
qui inclura les répertoires dans la liste des fichiers s'ils sont définis à true
.
klaw et klaw-sync sont à envisager pour ce genre de chose. Ces faisaient partie de node-fs-extra .
Voici encore une autre la mise en œuvre. Aucune des solutions ci-dessus n'a de limiteurs, et donc si votre structure de répertoire est grande, ils vont tous se bousculer et finir par manquer de ressources.
var async = require('async');
var fs = require('fs');
var resolve = require('path').resolve;
var scan = function(path, concurrency, callback) {
var list = [];
var walker = async.queue(function(path, callback) {
fs.stat(path, function(err, stats) {
if (err) {
return callback(err);
} else {
if (stats.isDirectory()) {
fs.readdir(path, function(err, files) {
if (err) {
callback(err);
} else {
for (var i = 0; i < files.length; i++) {
walker.push(resolve(path, files[i]));
}
callback();
}
});
} else {
list.push(path);
callback();
}
}
});
}, concurrency);
walker.push(path);
walker.drain = function() {
callback(list);
}
};
utilisant une simultanéité de 50 fonctionne assez bien, et est presque aussi rapide que des implémentations plus simples pour des structures de petits répertoires.
j'ai modifié Trevor Senior Promesse réponse de travailler avec Bluebird
var fs = require('fs'),
path = require('path'),
Promise = require('bluebird');
var readdirAsync = Promise.promisify(fs.readdir);
var statAsync = Promise.promisify(fs.stat);
function walkFiles (directory) {
var results = [];
return readdirAsync(directory).map(function(file) {
file = path.join(directory, file);
return statAsync(file).then(function(stat) {
if (stat.isFile()) {
return results.push(file);
}
return walkFiles(file).then(function(filesInDir) {
results = results.concat(filesInDir);
});
});
}).then(function() {
return results;
});
}
//use
walkDir(__dirname).then(function(files) {
console.log(files);
}).catch(function(e) {
console.error(e); {
});
pour le plaisir, voici une version à base de flux qui fonctionne avec highland.js flux de la bibliothèque. Il a été co-écrit par Victor Vu.
###
directory >---m------> dirFilesStream >---------o----> out
| |
| |
+--------< returnPipe <-----------+
legend: (m)erge (o)bserve
+ directory has the initial file
+ dirListStream does a directory listing
+ out prints out the full path of the file
+ returnPipe runs stat and filters on directories
###
_ = require('highland')
fs = require('fs')
fsPath = require('path')
directory = _(['someDirectory'])
mergePoint = _()
dirFilesStream = mergePoint.merge().flatMap((parentPath) ->
_.wrapCallback(fs.readdir)(parentPath).sequence().map (path) ->
fsPath.join parentPath, path
)
out = dirFilesStream
# Create the return pipe
returnPipe = dirFilesStream.observe().flatFilter((path) ->
_.wrapCallback(fs.stat)(path).map (v) ->
v.isDirectory()
)
# Connect up the merge point now that we have all of our streams.
mergePoint.write directory
mergePoint.write returnPipe
mergePoint.end()
# Release backpressure. This will print files as they are discovered
out.each H.log
# Another way would be to queue them all up and then print them all out at once.
# out.toArray((files)-> console.log(files))
utilisant des promesses ( Q ) pour résoudre ce dans un style fonctionnel:
var fs = require('fs'),
fsPath = require('path'),
Q = require('q');
var walk = function (dir) {
return Q.ninvoke(fs, 'readdir', dir).then(function (files) {
return Q.all(files.map(function (file) {
file = fsPath.join(dir, file);
return Q.ninvoke(fs, 'lstat', file).then(function (stat) {
if (stat.isDirectory()) {
return walk(file);
} else {
return [file];
}
});
}));
}).then(function (files) {
return files.reduce(function (pre, cur) {
return pre.concat(cur);
});
});
};
Il retourne une promesse d'un tableau, de sorte que vous pouvez l'utiliser comme:
walk('/home/mypath').then(function (files) { console.log(files); });
je dois ajouter la Promesse à base de sander de la bibliothèque à la liste.
var sander = require('sander');
sander.lsr(directory).then( filenames => { console.log(filenames) } );
avec Bluebird promise.coroutine:
let promise = require('bluebird'),
PC = promise.coroutine,
fs = promise.promisifyAll(require('fs'));
let getFiles = PC(function*(dir){
let files = [];
let contents = yield fs.readdirAsync(dir);
for (let i = 0, l = contents.length; i < l; i ++) {
//to remove dot(hidden) files on MAC
if (/^\..*/.test(contents[i])) contents.splice(i, 1);
}
for (let i = 0, l = contents.length; i < l; i ++) {
let content = path.resolve(dir, contents[i]);
let contentStat = yield fs.statAsync(content);
if (contentStat && contentStat.isDirectory()) {
let subFiles = yield getFiles(content);
files = files.concat(subFiles);
} else {
files.push(content);
}
}
return files;
});
//how to use
//easy error handling in one place
getFiles(your_dir).then(console.log).catch(err => console.log(err));
parce que chacun devrait écrire le sien, j'en ai fait un.
à pied(dir, cb, endCb) cb(fichier) endCb (err | null)
sale
module.exports = walk;
function walk(dir, cb, endCb) {
var fs = require('fs');
var path = require('path');
fs.readdir(dir, function(err, files) {
if (err) {
return endCb(err);
}
var pending = files.length;
if (pending === 0) {
endCb(null);
}
files.forEach(function(file) {
fs.stat(path.join(dir, file), function(err, stats) {
if (err) {
return endCb(err)
}
if (stats.isDirectory()) {
walk(path.join(dir, file), cb, function() {
pending--;
if (pending === 0) {
endCb(null);
}
});
} else {
cb(path.join(dir, file));
pending--;
if (pending === 0) {
endCb(null);
}
}
})
});
});
}
découvrez loaddir https://npmjs.org/package/loaddir
npm install loaddir
loaddir = require('loaddir')
allJavascripts = []
loaddir({
path: __dirname + '/public/javascripts',
callback: function(){ allJavascripts.push(this.relativePath + this.baseName); }
})
Vous pouvez utiliser fileName
au lieu de baseName
si vous avez besoin de l'extension.
un bonus ajouté est qu'il va regarder les fichiers ainsi et appeler le rappel à nouveau. Il y a des tonnes d'options de configuration pour le rendre extrêmement flexible.
je viens de refaire le guard
gemme de rubis à l'aide de loaddir dans peu de temps
C'est ma réponse. J'espère que ça peut aider quelqu'un.
mon objectif est de faire que la routine de recherche peut s'arrêter n'importe où, et pour un fichier trouvé, indique la profondeur relative par rapport au chemin original.
var _fs = require('fs');
var _path = require('path');
var _defer = process.nextTick;
// next() will pop the first element from an array and return it, together with
// the recursive depth and the container array of the element. i.e. If the first
// element is an array, it'll be dug into recursively. But if the first element is
// an empty array, it'll be simply popped and ignored.
// e.g. If the original array is [1,[2],3], next() will return [1,0,[[2],3]], and
// the array becomes [[2],3]. If the array is [[[],[1,2],3],4], next() will return
// [1,2,[2]], and the array becomes [[[2],3],4].
// There is an infinity loop `while(true) {...}`, because I optimized the code to
// make it a non-recursive version.
var next = function(c) {
var a = c;
var n = 0;
while (true) {
if (a.length == 0) return null;
var x = a[0];
if (x.constructor == Array) {
if (x.length > 0) {
a = x;
++n;
} else {
a.shift();
a = c;
n = 0;
}
} else {
a.shift();
return [x, n, a];
}
}
}
// cb is the callback function, it have four arguments:
// 1) an error object if any exception happens;
// 2) a path name, may be a directory or a file;
// 3) a flag, `true` means directory, and `false` means file;
// 4) a zero-based number indicates the depth relative to the original path.
// cb should return a state value to tell whether the searching routine should
// continue: `true` means it should continue; `false` means it should stop here;
// but for a directory, there is a third state `null`, means it should do not
// dig into the directory and continue searching the next file.
var ls = function(path, cb) {
// use `_path.resolve()` to correctly handle '.' and '..'.
var c = [ _path.resolve(path) ];
var f = function() {
var p = next(c);
p && s(p);
};
var s = function(p) {
_fs.stat(p[0], function(err, ss) {
if (err) {
// use `_defer()` to turn a recursive call into a non-recursive call.
cb(err, p[0], null, p[1]) && _defer(f);
} else if (ss.isDirectory()) {
var y = cb(null, p[0], true, p[1]);
if (y) r(p);
else if (y == null) _defer(f);
} else {
cb(null, p[0], false, p[1]) && _defer(f);
}
});
};
var r = function(p) {
_fs.readdir(p[0], function(err, files) {
if (err) {
cb(err, p[0], true, p[1]) && _defer(f);
} else {
// not use `Array.prototype.map()` because we can make each change on site.
for (var i = 0; i < files.length; i++) {
files[i] = _path.join(p[0], files[i]);
}
p[2].unshift(files);
_defer(f);
}
});
}
_defer(f);
};
var printfile = function(err, file, isdir, n) {
if (err) {
console.log('--> ' + ('[' + n + '] ') + file + ': ' + err);
return true;
} else {
console.log('... ' + ('[' + n + '] ') + (isdir ? 'D' : 'F') + ' ' + file);
return true;
}
};
var path = process.argv[2];
ls(path, printfile);
un autre simple et utile
function walkDir(root) {
const stat = fs.statSync(root);
if (stat.isDirectory()) {
const dirs = fs.readdirSync(root).filter(item => !item.startsWith('.'));
let results = dirs.map(sub => walkDir(`${root}/${sub}`));
return [].concat(...results);
} else {
return root;
}
}
je suis réticent à ajouter une autre réponse à la pile, mais j'ai aimé cette réponse (le seul qui a utilisé async/attente), mais j'ai pensé qu'il avait besoin d'un peu de rangement et de simplification:
async function getFileDescendents(dir) {
const fs = require('fs-promise'), path = require('path');
let files = await fs.readdir(dir);
let result = files.map(file => {
let p = path.join(dir,file);
return fs.stat(p).then(stat => stat.isDirectory() ? getFileDescendents(p) : p);
});
return Array.prototype.concat(...(await Promise.all(result))); // flatten
}
il est utilisé comme ceci:
let files = await getFileDescendents('./my_directory');
C'est comme ça que j'utilise les nodejs fs.fonction readdir pour effectuer une recherche récursive dans un répertoire.
const fs = require('fs');
const mime = require('mime-types');
const readdirRecursivePromise = path => {
return new Promise((resolve, reject) => {
fs.readdir(path, (err, directoriesPaths) => {
if (err) {
reject(err);
} else {
if (directoriesPaths.indexOf('.DS_Store') != -1) {
directoriesPaths.splice(directoriesPaths.indexOf('.DS_Store'), 1);
}
directoriesPaths.forEach((e, i) => {
directoriesPaths[i] = statPromise(`${path}/${e}`);
});
Promise.all(directoriesPaths).then(out => {
resolve(out);
}).catch(err => {
reject(err);
});
}
});
});
};
const statPromise = path => {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if (err) {
reject(err);
} else {
if (stats.isDirectory()) {
readdirRecursivePromise(path).then(out => {
resolve(out);
}).catch(err => {
reject(err);
});
} else if (stats.isFile()) {
resolve({
'path': path,
'type': mime.lookup(path)
});
} else {
reject(`Error parsing path: ${path}`);
}
}
});
});
};
const flatten = (arr, result = []) => {
for (let i = 0, length = arr.length; i < length; i++) {
const value = arr[i];
if (Array.isArray(value)) {
flatten(value, result);
} else {
result.push(value);
}
}
return result;
};
disons que vous avez un chemin appelé '/database' dans votre root de projets de noeuds. Une fois cette promesse résolue, elle devrait recracher un tableau de chaque fichier sous '/database'.
readdirRecursivePromise('database').then(out => {
console.log(flatten(out));
}).catch(err => {
console.log(err);
});
encore une autre réponse, mais cette fois en utilisant dactylographié:
/**
* Recursively walk a directory asynchronously and obtain all file names (with full path).
*
* @param dir Folder name you want to recursively process
* @param done Callback function, returns all files with full path.
* @param filter Optional filter to specify which files to include,
* e.g. for json files: (f: string) => /.json$/.test(f)
*/
const walk = (
dir: string,
done: (err: Error | null, results ? : string[]) => void,
filter ? : (f: string) => boolean
) => {
let results: string[] = [];
fs.readdir(dir, (err: Error, list: string[]) => {
if (err) {
return done(err);
}
let pending = list.length;
if (!pending) {
return done(null, results);
}
list.forEach((file: string) => {
file = path.resolve(dir, file);
fs.stat(file, (err2, stat) => {
if (stat && stat.isDirectory()) {
walk(file, (err3, res) => {
if (res) {
results = results.concat(res);
}
if (!--pending) {
done(null, results);
}
}, filter);
} else {
if (typeof filter === 'undefined' || (filter && filter(file))) {
results.push(file);
}
if (!--pending) {
done(null, results);
}
}
});
});
});
};