Existem basicamente duas maneiras de conseguir isso. Em um ambiente assíncrono, você notará que existem dois tipos de loops: serial e paralelo. Um loop serial espera que uma iteração seja concluída antes de passar para a próxima iteração - isso garante que todas as iterações do loop sejam concluídas em ordem. Em um loop paralelo, todas as iterações são iniciadas ao mesmo tempo e uma pode ser concluída antes da outra, no entanto, é muito mais rápida que um loop serial. Portanto, nesse caso, provavelmente é melhor usar um loop paralelo, porque não importa em que ordem a caminhada é concluída, desde que ela complete e retorne os resultados (a menos que você os queira em ordem).
Um loop paralelo ficaria assim:
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);
}
});
});
});
};
Um loop serial ficaria assim:
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 i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = path.resolve(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();
}
});
})();
});
};
E para testá-lo em seu diretório pessoal (AVISO: a lista de resultados será enorme se você tiver muitas coisas em seu diretório pessoal):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
EDIT: Exemplos aprimorados.
file = dir + '/' + file;
Isto não é recomendado. Você deve usar:var path = require('path'); file = path.resolve(dir, file);
path.resolve(...)
você vai ter um caminho adequado se você está no Windows ou Unix :) O que significa que você vai obter algo comoC:\\some\\foo\\path
no Windows e/some/foo/path
em sistemas Unixrequire('node-dir').files(__dirname, function(err, files) { console.log(files); });
!--
sintaxe, uma pergunta foi feita sobre isso #Este usa a quantidade máxima de recursos novos e buzzwordy disponíveis no nó 8, incluindo Promessas, util / promisify, desestruturação, espera assíncrona, mapa + redução e muito mais, fazendo com que seus colegas de trabalho coçam a cabeça enquanto tentam descobrir o que está acontecendo.
Nó 8+
Sem dependências externas.
Uso
Nó 10.10+
Atualizado para o nó 10+ com ainda mais whizbang:
Observe que a partir do nó 11.15.0 você pode usar em
files.flat()
vez deArray.prototype.concat(...files)
achatar a matriz de arquivos.Nó 11+
Se você quiser explodir completamente a cabeça de todos, use a versão a seguir usando iteradores assíncronos . Além de ser muito legal, também permite que os consumidores obtenham resultados um de cada vez, tornando-o mais adequado para diretórios realmente grandes.
O uso mudou porque o tipo de retorno agora é um iterador assíncrono em vez de uma promessa
Caso alguém esteja interessado, escrevi mais sobre iteradores assíncronos aqui: https://qwtel.com/posts/software/async-generators-in-the-wild/
fonte
subdir
esubdirs
é enganosa, pois esses podem ser realmente arquivos (sugiro algo comoitemInDir
ouitem_in_dir
ou simplesmenteitem
). Mas essa solução parece mais limpa que a aceita e é muito menos código. Também não acho muito mais complicado que o código na resposta aceita. +1require(fs).promises
e simplesmente soltarutil.promisify
completamente. Pessoalmente, eu alias fs para fs.promises.readdir
AKA, como o objeto de opções, parareaddir(dir, {withFileTypes: true})
retornar todos os itens com suas informações de tipo, para que não precisemos ligarstat
para obter as informações quereaddir
agora nos fornecem costas. Isso evita a necessidade de fazer chamadas sys adicionais. Detalhes aquiwithFileTypes
. Obrigado pela dica.return Array.prototype.concat(...files);
por,let result = Array.prototype.concat(...files); return result.map(file => file.split('\\').join('/'));
certifique-se de que os dirs retornem um "/" e não um "\". Se você não se importa com regex, você também pode fazerreturn result.map(file => file.replace(/\\/g, '/'));
Apenas no caso de alguém achar útil, eu também montei uma versão síncrona .
Dica: Para usar menos recursos ao filtrar. Filtre dentro dessa própria função. Por exemplo, substitua
results.push(file);
pelo código abaixo. Ajuste conforme necessário:fonte
lstat
vez disso? Ou então, adicione uma verificação de recursividade para limitar o nível de recursividade.A. Dê uma olhada no módulo de arquivo . Tem uma função chamada walk:
Isso pode ser para você! E sim, é assíncrono. No entanto, acho que você teria que agregar o caminho completo, se necessário.
B. Uma alternativa, e até uma das minhas favoritas: use o unix
find
para isso. Por que fazer algo de novo, que já foi programado? Talvez não seja exatamente o que você precisa, mas ainda vale a pena conferir:O Find possui um bom mecanismo de armazenamento interno que torna as pesquisas subseqüentes muito rápidas, desde que apenas poucas pastas tenham sido alteradas.
fonte
Outro bom pacote npm é o glob .
npm install glob
É muito poderoso e deve cobrir todas as suas necessidades recorrentes.
Editar:
Na verdade, eu não estava perfeitamente feliz com a glob, então criei readdirp .
Estou muito confiante de que sua API facilita a localização de arquivos e diretórios de forma recursiva e a aplicação de filtros específicos.
Leia a documentação para ter uma idéia melhor do que ele faz e instale via:
npm install readdirp
fonte
Eu recomendo usar o node-glob para realizar essa tarefa.
fonte
Se você deseja usar um pacote npm, a chave inglesa é muito boa.
EDIT (2018):
qualquer pessoa que esteja lendo recentemente: o autor reprovou este pacote em 2015:
fonte
denodify
isso? O retorno de chamada é disparado várias vezes (recursivamente). Portanto, o usoQ.denodify(wrench.readdirRecursive)
retorna apenas o primeiro resultado.Adorei a resposta do chjj acima e não teria sido capaz de criar minha versão do loop paralelo sem esse início.
Eu criei um Gist também. Comentários bem-vindos. Ainda estou começando no domínio do NodeJS, e é dessa maneira que espero aprender mais.
fonte
Com recursão
Chamando
fonte
/
mas utilizando opath
módulo:path.join(searchPath, file)
. Dessa forma, você obterá os caminhos corretos, independentemente do sistema operacional.Use node-dir para produzir exatamente a saída que você deseja
fonte
Eu codifiquei isso recentemente e achei que faria sentido compartilhar isso aqui. O código faz uso da biblioteca assíncrona .
Você pode usá-lo assim:
fonte
Uma biblioteca chamada Filehound é outra opção. Ele procurará recursivamente um determinado diretório (diretório de trabalho por padrão). Ele suporta vários filtros, retornos de chamada, promessas e pesquisas de sincronização.
Por exemplo, pesquise no diretório de trabalho atual todos os arquivos (usando retornos de chamada):
Ou promete e especificando um diretório específico:
Consulte os documentos para obter mais casos de uso e exemplos de uso: https://github.com/nspragg/filehound
Disclaimer: Eu sou o autor.
fonte
Usando async / waitit, isso deve funcionar:
Você pode usar o bluebird.Promisify ou este:
Veja minha outra resposta para uma abordagem de gerador que pode fornecer resultados ainda mais rápidos.
fonte
Assíncrono
Sincronizar
Legível assíncrona
Nota: ambas as versões seguirão links simbólicos (iguais ao original
fs.readdir
)fonte
Confira a biblioteca final-fs . Ele fornece uma
readdirRecursive
função:fonte
Implementação de promessa autônoma
Estou usando a biblioteca when.js promessa neste exemplo.
Incluí um parâmetro opcional
includeDir
que incluirá diretórios na lista de arquivos, se definido comotrue
.fonte
vale a pena considerar o klaw e o klaw-sync para esse tipo de coisa. Isso fazia parte do node-fs-extra .
fonte
Aqui está mais uma implementação. Nenhuma das soluções acima possui limitadores e, portanto, se sua estrutura de diretórios for grande, todas elas serão danificadas e eventualmente ficarão sem recursos.
Usar uma simultaneidade de 50 funciona muito bem e é quase tão rápido quanto as implementações mais simples para estruturas de diretório pequenas.
fonte
O módulo recursive-readdir possui essa funcionalidade.
fonte
Modifiquei a resposta baseada em Promessas de Trevor Senior para trabalhar com o Bluebird
fonte
Por diversão, aqui está uma versão baseada em fluxo que funciona com a biblioteca de fluxos highland.js. Foi co-autoria de Victor Vu.
fonte
Usando promessas ( Q ) para resolver isso em um estilo funcional:
Ele retorna a promessa de uma matriz, para que você possa usá-lo como:
fonte
Devo adicionar a biblioteca de lixadeira baseada em promessa à lista.
fonte
Usando a promessa bluebird.coroutine:
fonte
Porque todo mundo deveria escrever o seu, eu fiz um.
walk (dir, cb, endCb) cb (arquivo) endCb (err | nulo)
SUJO
fonte
confira loaddir https://npmjs.org/package/loaddir
npm install loaddir
Você pode usar em
fileName
vez debaseName
se precisar da extensão também.Um bônus adicional é que ele também assiste os arquivos e chama o retorno de chamada novamente. Existem inúmeras opções de configuração para torná-lo extremamente flexível.
Acabei
guard
de refazer a gema do ruby usando o loaddir em pouco tempofonte
Esta é a minha resposta. Espero que possa ajudar alguém.
Meu foco é fazer com que a rotina de pesquisa possa parar em qualquer lugar e, para um arquivo encontrado, informe a profundidade relativa do caminho original.
fonte
Aqui está um método recursivo de obter todos os arquivos, incluindo subdiretórios.
fonte
Outro simples e útil
fonte
É assim que uso a função nodejs fs.readdir para pesquisar recursivamente um diretório.
Digamos que você tenha um caminho chamado '/ database' na raiz de seus projetos de nós. Depois que essa promessa é resolvida, ela deve cuspir uma matriz de todos os arquivos em '/ database'.
fonte