Suchen Sie Dateien nach Erweiterung * .html in einem Ordner in nodejs


88

Ich möchte alle * .html-Dateien im src-Ordner und alle seine Unterordner mit nodejs finden. Was ist der beste Weg, um es zu tun?

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);

Ich denke, viele Entwickler sollten eine großartige und getestete Lösung haben, und es ist besser, sie zu verwenden, als selbst eine zu schreiben.


Wenn Sie Dateien nach Regex durchsuchen möchten, verwenden Sie die Datei-Regex- Bibliothek, die gleichzeitig eine rekursive Dateisuche durchführt.
Akash Babu

Antworten:


90

node.js, rekursive einfache Funktion:

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');

Fügen Sie RegExp hinzu, wenn Sie Lust haben, und einen Rückruf, um es generisch zu machen.

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);
});

Vielen Dank für den Demo-Code! Ich habe etwas über Ihren Code hinzugefügt und es funktioniert großartig! Ich habe auch Ihr LiteScript-Projekt überprüft und es ist erstaunlich. Ich habe es auf Github gespielt!
Nicolas S.Xu

Nettes kleines Skript zum Finden von Dateinamen ohne Erweiterung - in meinem Fall hatte ich einige JPEGs und musste herausfinden, ob die Originaldatei in einem anderen Verzeichnis PNG oder JPEG war, das hilft
Ricky Odin Matthews

77

Ich benutze gerne das Glob- Paket:

const glob = require('glob');

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

1
Normalerweise kein Fan von Paketen für einfache Dinge, aber es ist nur eine Frage der Zeit, bis glob eine integrierte Implementierung von Node Js hat. Dies wird sozusagen zum regulären Ausdruck der Dateiauswahl.
Seph Reed

26

Was, Moment mal?! ... Okay, vielleicht macht das auch für andere Sinn.

[ nodejs 7 wohlgemerkt ]

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

Was auch immer mit Regex tun, machen Sie es zu einem Argument, das Sie in der Funktion mit einem Standardwert usw. festgelegt haben.


2
Dadurch werden nur übereinstimmende Dateien im Stammverzeichnis abgerufen.
Dreamerkumar

6
Ich habe versucht zu bearbeiten und wurde abgelehnt, was ich nicht zustimme. Hier ist mein Vorschlag: stackoverflow.com/review/suggested-edits/19188733 wl macht so viel Sinn. Auch der Import für fs fehlt. Die drei Zeilen, die Sie benötigen, sind: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Avindra Goolcharan

richtig sorry wl.fs ist wo ich die fs lib per import gespeichert habe.
Meister James

Oh, Import ist wahrscheinlich meine eigene benutzerdefinierte Funktion, die auch jetzt angezeigt werden muss. Verwenden Sie also erforderlich oder was auch immer Sie tun müssen.
Meister James

13

Basierend auf Lucios Code habe ich ein Modul erstellt. Es werden alle Dateien mit bestimmten Erweiterungen unter der einen entfernt. Poste es einfach hier, falls jemand es braucht.

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

Sie können dazu Filehound verwenden.

Beispiel: Finden Sie alle HTML-Dateien 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);
});

Weitere Informationen (und Beispiele) finden Sie in den Dokumenten: https://github.com/nspragg/filehound

Haftungsausschluss : Ich bin der Autor.


8

Ich habe mir die obigen Antworten angesehen und diese Version gemischt, die für mich funktioniert:

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

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

Dieser Test gibt ein Array von Dateinamen aus den Dateien zurück, die sich im Ordner im Pfad befinden ./testdata. Arbeiten an der Knotenversion 8.11.3.


1
Ich würde $ am Ende des RegExp hinzufügen:.*\.(${extension})$
Eugene

3

Sie können hierfür die Betriebssystemhilfe verwenden. Hier ist eine plattformübergreifende Lösung:

1. Die Balgfunktion verwendet lsund dirund sucht nicht rekursiv, hat jedoch relative Pfade

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. Die folgende Funktion verwendet findund dirsucht rekursiv, hat jedoch unter Windows absolute Pfade

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
Ich hätte nie gedacht, dass es so gemacht werden könnte, da ich mit dem Require ('child_process'). Exec nicht vertraut bin, aber es sieht sehr gut aus und inspiriert mich zu vielen Gedanken. Vielen Dank!
Nicolas S.Xu

2
Dies ist nicht der Weg, dies "mit nodejs" zu tun. Dies verwendet das Betriebssystem, startet einen anderen Prozess usw. Es schlägt auch fehl, wenn ein Verzeichnis mit ".html" endet, z. B.: Files.html /
Lucio M. Tato

@ LucioM.Tato Sie können bei der Suche den Dateityp angeben. Es gibt viele Lösungen für ein Problem. Wenn eine nicht zu Ihrer Idee passt, heißt das nicht, dass sie falsch ist, sondern nur anders. Diese Antwort zeigt, dass Sie vorhandene Lösungen unabhängig von der verwendeten Skriptsprache wiederverwenden können.
Emil Condrea

Natürlich ist das nichts Falsches daran, ein Verzeichnis zu durchlaufen und die Dateien mit einer bestimmten Erweiterung zu finden, aber ich wollte nur all diese Informationen vom Betriebssystem erhalten, weil ich wusste, dass er das kann. :)
Emil Condrea

@EmilCondrea, IHMO Dies ist kein "Knoten verwenden", wie das OP gefragt hat. Wie auch immer, ich werde die Ablehnung entfernen, wenn dich das stört.
Lucio M. Tato

3

Der folgende Code führt eine rekursive Suche in ./ durch (ändern Sie sie entsprechend) und gibt ein Array absoluter Dateinamen zurück, die mit .html enden

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

Aufgrund des guten Rufs kann kein Kommentar hinzugefügt werden. Beachten Sie jedoch Folgendes:

Die Verwendung von fs.readdir oder node-glob zum Suchen eines Platzhalter-Satzes von Dateien in einem Ordner mit 500.000 Dateien dauerte ~ 2 Sekunden. Die Verwendung von exec mit DIR dauerte ~ 0,05 s (nicht rekursiv) oder ~ 0,45 s (rekursiv). (Ich habe nach ~ 14 Dateien gesucht, die meinem Muster in einem einzigen Verzeichnis entsprechen).

Bisher konnte ich keine NodeJS-Implementierung finden, die auf der Suche nach Effizienz einen Platzhalter auf niedriger Ebene verwendet. Aber der obige DIR / ls-basierte Code funktioniert in Windows in Bezug auf Effizienz wunderbar. Linux Find wird jedoch für große Verzeichnisse wahrscheinlich sehr langsam sein .


In der Tat interessant.
Philk

Hinweis Ich sehe, dass das neueste nodejs fs-Modul neue Funktionen enthält (12.13+? Iteriertes Verzeichnis fns?). Ich habe sie noch nicht ausprobiert, weil ich vorerst am 6.9.11 festsitze. Es wird interessant sein zu sehen, ob sie neue nützliche Funktionen dafür bieten. Ich denke jetzt an meinen Beitrag. OS-Caching sollte ebenfalls berücksichtigt werden. Meine 0,05er wären wahrscheinlich gemessen worden, nachdem ich sie mehrmals ausgeführt hatte. Ich frage mich, wie hoch die ERSTE 'DIR'-Geschwindigkeit ist.
Simon H

1

meine zwei Pence, mit Karte anstelle von for-Schleife

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);

1

Werfen Sie einen Blick in File-Regex

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

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

Dieses obige Snippet würde alle jsDateien im aktuellen Verzeichnis drucken .


Das ist eigentlich die einfachste Lösung da draußen.
Kyeno

0

Ich habe gerade bemerkt, dass Sie Sync-Fs-Methoden verwenden, die Ihre Anwendung blockieren könnten. Hier ist eine vielversprechende asynchrone Methode mit Async und q . Sie können sie mit dem START = / myfolder FILTER = ". Jpg" -Knoten myfile.js ausführen. Angenommen, Sie fügen den folgenden Code in eine Datei mit dem Namen myfile.js ein:

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
Ein großartiges Beispiel für die Hölle des Rückrufs! :)
Afshin Moazami

2
Sie haben Recht, würden es nicht noch einmal so machen: D Vielleicht finde ich in den nächsten Tagen Zeit und löse es mit asynchron / warte darauf, den Unterschied zu zeigen.
Christoph Johannsdotter

0

Installieren

Sie können dieses Paket Walk-Sync von installieren

yarn add walk-sync

Verwendung

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

-2

Alter Beitrag, aber ES6 behandelt dies jetzt sofort mit der includesMethode.

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

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

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

Ich werde dies verbessern, weil ich file.readdirSynceine einfache Möglichkeit zum Filtern von Dateien nach Erweiterung verwendet habe und brauchte. Ich denke, dies beantwortet einen Teil der Frage in diesem Thread, aber vielleicht nicht alles. Immer noch eine Überlegung wert.
justinpage
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.