trova i file per estensione, * .html in una cartella in nodejs


92

Mi piacerebbe trovare tutti i file * .html nella cartella src e in tutte le sue sottocartelle usando nodejs. Qual'è il miglior modo di farlo?

var folder = '/project1/src';
var extension = 'html';
var cb = function(err, results) {
   // results is an array of the files with path relative to the folder
   console.log(results);

}
// This function is what I am looking for. It has to recursively traverse all sub folders. 
findFiles(folder, extension, cb);

Penso che molti sviluppatori dovrebbero avere una soluzione fantastica e testata ed è meglio usarla che scriverne una da solo.


Se si desidera cercare i file tramite regex, utilizzare la libreria file-regex , che esegue contemporaneamente la ricerca di file ricorsiva.
Akash Babu

Risposte:


92

node.js, funzione semplice ricorsiva:

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

function fromDir(startPath,filter){

    //console.log('Starting from dir '+startPath+'/');

    if (!fs.existsSync(startPath)){
        console.log("no dir ",startPath);
        return;
    }

    var files=fs.readdirSync(startPath);
    for(var i=0;i<files.length;i++){
        var filename=path.join(startPath,files[i]);
        var stat = fs.lstatSync(filename);
        if (stat.isDirectory()){
            fromDir(filename,filter); //recurse
        }
        else if (filename.indexOf(filter)>=0) {
            console.log('-- found: ',filename);
        };
    };
};

fromDir('../LiteScript','.html');

aggiungi RegExp se vuoi essere fantasioso e una richiamata per renderlo generico.

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

function fromDir(startPath,filter,callback){

    //console.log('Starting from dir '+startPath+'/');

    if (!fs.existsSync(startPath)){
        console.log("no dir ",startPath);
        return;
    }

    var files=fs.readdirSync(startPath);
    for(var i=0;i<files.length;i++){
        var filename=path.join(startPath,files[i]);
        var stat = fs.lstatSync(filename);
        if (stat.isDirectory()){
            fromDir(filename,filter,callback); //recurse
        }
        else if (filter.test(filename)) callback(filename);
    };
};

fromDir('../LiteScript',/\.html$/,function(filename){
    console.log('-- found: ',filename);
});

grazie mille per il codice demo! Ho aggiunto qualcosa al tuo codice e funziona benissimo! Ho anche controllato il tuo progetto LiteScript ed è fantastico. L'ho recitato su GitHub!
Nicolas S.Xu

Simpatico script per trovare anche nomi di file senza estensione - nel mio caso avevo alcuni Jpeg e avevo bisogno di trovare se il file originale in una directory diversa era png o jpeg, questo aiuta
Ricky Odin Matthews

80

mi piace usare il pacchetto glob :

const glob = require('glob');

glob(__dirname + '/**/*.html', {}, (err, files)=>{
  console.log(files)
})

1
Normalmente non è un fan dei pacchetti per cose semplici, ma è solo una questione di tempo prima che glob abbia un'implementazione di node js incorporata. Questa è una specie di diventare la regexp della selezione dei file.
Seph Reed

27

Cosa, aspetta ?! ... Okay, forse questo ha più senso anche per qualcun altro.

[ nodejs 7 intendiamoci ]

fs = import('fs');
let dirCont = fs.readdirSync( dir );
let files = dirCont.filter( function( elm ) {return elm.match(/.*\.(htm?html)/ig);});

Fai qualsiasi cosa con regex rendilo un argomento che hai impostato nella funzione con un valore predefinito ecc.


2
Questo otterrà solo i file corrispondenti nella directory principale.
dreamerkumar

6
Ho provato a modificare e sono stato rifiutato, cosa con cui non sono d'accordo. Ecco la mia proposta: stackoverflow.com/review/suggested-edits/19188733 wl ha davvero senso. Manca anche l'importazione per fs. Le tre linee di cui hai bisogno sono: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Avindra Goolcharan

proprio scusa wl.fs è dove ho memorizzato la lib di fs tramite import.
Master James,

oh, l'importazione è probabilmente la mia funzione personalizzata che punta a richiedere anche per ora, quindi sicuramente l'uso richiede o qualunque cosa tu debba fare.
Master James,

13

Sulla base del codice di Lucio, ho realizzato un modulo. Restituirà una via con tutti i file con estensioni specifiche sotto quella. Pubblicalo qui nel caso qualcuno ne abbia bisogno.

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


/**
 * Find all files recursively in specific folder with specific extension, e.g:
 * findFilesInDir('./project/src', '.html') ==> ['./project/src/a.html','./project/src/build/index.html']
 * @param  {String} startPath    Path relative to this file or other file which requires this files
 * @param  {String} filter       Extension name, e.g: '.html'
 * @return {Array}               Result files with path string in an array
 */
function findFilesInDir(startPath,filter){

    var results = [];

    if (!fs.existsSync(startPath)){
        console.log("no dir ",startPath);
        return;
    }

    var files=fs.readdirSync(startPath);
    for(var i=0;i<files.length;i++){
        var filename=path.join(startPath,files[i]);
        var stat = fs.lstatSync(filename);
        if (stat.isDirectory()){
            results = results.concat(findFilesInDir(filename,filter)); //recurse
        }
        else if (filename.indexOf(filter)>=0) {
            console.log('-- found: ',filename);
            results.push(filename);
        }
    }
    return results;
}

module.exports = findFilesInDir;

12

Puoi usare Filehound per farlo.

Ad esempio: trova tutti i file .html in / tmp:

const Filehound = require('filehound');

Filehound.create()
  .ext('html')
  .paths("/tmp")
  .find((err, htmlFiles) => {
    if (err) return console.error("handle err", err);

    console.log(htmlFiles);
});

Per ulteriori informazioni (ed esempi), controlla i documenti: https://github.com/nspragg/filehound

Disclaimer : sono l'autore.


8

Ho esaminato le risposte sopra e ho mescolato questa versione che funziona per me:

function getFilesFromPath(path, extension) {
    let files = fs.readdirSync( path );
    return files.filter( file => file.match(new RegExp(`.*\.(${extension})`, 'ig')));
}

console.log(getFilesFromPath("./testdata", ".txt"));

Questo test restituirà un array di nomi di file dai file trovati nella cartella nel percorso ./testdata. Lavorare sulla versione del nodo 8.11.3.


1
Aggiungerei $ alla fine della RegExp:.*\.(${extension})$
Eugene

3

È possibile utilizzare la guida del sistema operativo per questo. Ecco una soluzione multipiattaforma:

1. La funzione seguente usa lsand dire non ricerca ricorsivamente ma ha percorsi relativi

var exec = require('child_process').exec;
function findFiles(folder,extension,cb){
    var command = "";
    if(/^win/.test(process.platform)){
        command = "dir /B "+folder+"\\*."+extension;
    }else{
        command = "ls -1 "+folder+"/*."+extension;
    }
    exec(command,function(err,stdout,stderr){
        if(err)
            return cb(err,null);
        //get rid of \r from windows
        stdout = stdout.replace(/\r/g,"");
        var files = stdout.split("\n");
        //remove last entry because it is empty
        files.splice(-1,1);
        cb(err,files);
    });
}

findFiles("folderName","html",function(err,files){
    console.log("files:",files);
})

2. La funzione seguente usa finde dir, cerca ricorsivamente ma su Windows ha percorsi assoluti

var exec = require('child_process').exec;
function findFiles(folder,extension,cb){
    var command = "";
    if(/^win/.test(process.platform)){
        command = "dir /B /s "+folder+"\\*."+extension;
    }else{
        command = 'find '+folder+' -name "*.'+extension+'"'
    }
    exec(command,function(err,stdout,stderr){
        if(err)
            return cb(err,null);
        //get rid of \r from windows
        stdout = stdout.replace(/\r/g,"");
        var files = stdout.split("\n");
        //remove last entry because it is empty
        files.splice(-1,1);
        cb(err,files);
    });
}

findFiles("folder","html",function(err,files){
    console.log("files:",files);
})

1
Non avrei mai pensato che si potesse fare in questo modo, dato che non ho familiarità con require ('child_process'). Exec, ma sembra molto buono e ispira molti pensieri in me. Grazie!
Nicolas S.Xu

2
Questo non è il modo per farlo "usando nodejs". Questo sta usando il sistema operativo, lanciando un altro processo, ecc. Inoltre non riesce se c'è una directory che termina in ".html", ad esempio: files.html /
Lucio M. Tato

@ LucioM.Tato puoi specificare il tipo di file durante la ricerca. Ci sono molte soluzioni a un problema, se una non corrisponde alla tua idea, semplicemente non significa che sia sbagliata, è solo diversa. Questa risposta dimostra che è possibile riutilizzare le soluzioni esistenti indipendentemente dal linguaggio di scripting utilizzato.
Emil Condrea

Ovviamente non c'è niente di sbagliato nell'iterare su una directory e trovare i file con una certa estensione, ma volevo solo ricevere tutte queste informazioni dal sistema operativo perché sapevo che poteva farlo. :)
Emil Condrea

@EmilCondrea, IHMO questo non "utilizza il nodo" come richiesto dall'OP. Comunque rimuoverò il voto negativo se ti dà fastidio.
Lucio M. Tato

3

Il codice seguente esegue una ricerca ricorsiva all'interno di ./ (modificalo in modo appropriato) e restituisce un array di nomi di file assoluti che terminano con .html

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

var searchRecursive = function(dir, pattern) {
  // This is where we store pattern matches of all files inside the directory
  var results = [];

  // Read contents of directory
  fs.readdirSync(dir).forEach(function (dirInner) {
    // Obtain absolute path
    dirInner = path.resolve(dir, dirInner);

    // Get stats to determine if path is a directory or a file
    var stat = fs.statSync(dirInner);

    // If path is a directory, scan it and combine results
    if (stat.isDirectory()) {
      results = results.concat(searchRecursive(dirInner, pattern));
    }

    // If path is a file and ends with pattern then push it onto results
    if (stat.isFile() && dirInner.endsWith(pattern)) {
      results.push(dirInner);
    }
  });

  return results;
};

var files = searchRecursive('./', '.html'); // replace dir and pattern
                                                // as you seem fit

console.log(files);

2

Dai un'occhiata a file-regex

let findFiles = require('file-regex')
let pattern = '\.js'

findFiles(__dirname, pattern, (err, files) => {  
   console.log(files);
})

Questo frammento sopra stamperà tutti i jsfile nella directory corrente.


In realtà è la soluzione più semplice in circolazione.
kyeno

2

Non è possibile aggiungere un commento a causa della reputazione, ma nota quanto segue:

L'utilizzo di fs.readdir o node-glob per trovare un set di file con caratteri jolly in una cartella di 500.000 file ha richiesto circa 2 secondi. L'uso di exec con DIR ha richiesto ~ 0,05 s (non ricorsivo) o ~ 0,45 s (ricorsivo). (Stavo cercando ~ 14 file corrispondenti al mio modello in una singola directory).

Finora, non sono riuscito a trovare alcuna implementazione di nodejs che utilizzi caratteri jolly del sistema operativo di basso livello alla ricerca di efficienza. Ma il codice basato su DIR / l di cui sopra funziona meravigliosamente in Windows in termini di efficienza. linux find, tuttavia, sarà probabilmente molto lento per directory di grandi dimensioni.


Interessante, davvero.
philk

Nota Vedo che ci sono nuove funzioni nell'ultimo modulo fs di nodejs (12.13+? Directory iterata fns?). Non li ho ancora provati perché per ora sono bloccato sul 6.9.11; sarà interessante vedere se forniscono nuove funzionalità utili per questo. Pensando al mio post adesso; Si dovrebbe anche considerare la memorizzazione nella cache del sistema operativo. Probabilmente i miei 0,05 sarebbero stati misurati DOPO averlo eseguito un certo numero di volte. Mi chiedo quale sia la PRIMA velocità "DIR"?
Simon H

1

i miei due pence, usando map al posto di for-loop

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

var findFiles = function(folder, pattern = /.*/, callback) {
  var flist = [];

  fs.readdirSync(folder).map(function(e){ 
    var fname = path.join(folder, e);
    var fstat = fs.lstatSync(fname);
    if (fstat.isDirectory()) {
      // don't want to produce a new array with concat
      Array.prototype.push.apply(flist, findFiles(fname, pattern, callback)); 
    } else {
      if (pattern.test(fname)) {
        flist.push(fname);
        if (callback) {
          callback(fname);
        }
      }
    }
  });
  return flist;
};

// HTML files   
var html_files = findFiles(myPath, /\.html$/, function(o) { console.log('look what we have found : ' + o} );

// All files
var all_files = findFiles(myPath);

0

Ho appena notato, si sta utilizzando metodi fs di sincronizzazione, che potrebbe bloccare voi l'applicazione, ecco una promessa basata asincrone modo utilizzando asincrona e q , è possibile eseguire con Start = / MyFolder myfile.js FILTER = "jpg" nodo, supponendo che tu abbia inserito il seguente codice in un file chiamato myfile.js:

Q = require("q")
async = require("async")
path = require("path")
fs = require("fs")

function findFiles(startPath, filter, files){
    var deferred;
    deferred = Q.defer(); //main deferred

    //read directory
    Q.nfcall(fs.readdir, startPath).then(function(list) {
        var ideferred = Q.defer(); //inner deferred for resolve of async each
        //async crawling through dir
        async.each(list, function(item, done) {

            //stat current item in dirlist
            return Q.nfcall(fs.stat, path.join(startPath, item))
                .then(function(stat) {
                    //check if item is a directory
                    if (stat.isDirectory()) {
                        //recursive!! find files in subdirectory
                        return findFiles(path.join(startPath, item), filter, files)
                            .catch(function(error){
                                console.log("could not read path: " + error.toString());
                            })
                            .finally(function() {
                                //resolve async job after promise of subprocess of finding files has been resolved
                                return done();
                             });
                    //check if item is a file, that matches the filter and add it to files array
                    } else if (item.indexOf(filter) >= 0) {
                        files.push(path.join(startPath, item));
                        return done();
                    //file is no directory and does not match the filefilter -> don't do anything
                    } else {
                        return done();
                    }
                })
                .catch(function(error){
                    ideferred.reject("Could not stat: " + error.toString());
                });
        }, function() {
            return ideferred.resolve(); //async each has finished, so resolve inner deferred
        });
        return ideferred.promise;
    }).then(function() {
        //here you could do anything with the files of this recursion step (otherwise you would only need ONE deferred)
        return deferred.resolve(files); //resolve main deferred
    }).catch(function(error) {
        deferred.reject("Could not read dir: " + error.toString());
        return
    });
    return deferred.promise;
}


findFiles(process.env.START, process.env.FILTER, [])
    .then(function(files){
        console.log(files);
    })
    .catch(function(error){
        console.log("Problem finding files: " + error);
})

4
Un ottimo esempio di callback hell! :)
Afshin Moazami

2
hai ragione, non lo rifarei in questo modo: D Forse troverò il tempo nei prossimi giorni, risolvendolo con async / attendere per mostrare la differenza.
Christoph Johannsdotter

0

Installare

puoi installare questo pacchetto walk-sync con

yarn add walk-sync

Utilizzo

const walkSync = require("walk-sync");
const paths = walkSync("./project1/src", {globs: ["**/*.html"]});
console.log(paths);   //all html file path array

-2

Il vecchio post ma ES6 ora gestisce questo fuori dagli schemi con il includesmetodo.

let files = ['file.json', 'other.js'];

let jsonFiles = files.filter(file => file.includes('.json'));

console.log("Files: ", jsonFiles) ==> //file.json

Vorrei votare questo perché stavo usando file.readdirSynce avevo bisogno di un modo semplice per filtrare i file per estensione. Penso che questo risponda a una parte della domanda in questo thread ma forse non a tutto. Vale ancora la pena considerare.
justinpage
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.