nodejs'deki bir klasörün altındaki uzantıya, * .html'ye göre dosyaları bulun


92

Src klasöründeki tüm * .html dosyalarını ve nodejs kullanarak tüm alt klasörlerini bulmak istiyorum. Bunu yapmanın en iyi yolu ne?

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

Bir çok geliştiricinin harika ve test edilmiş bir çözüme sahip olması gerektiğini düşünüyorum ve bunu kendim yazmaktansa kullanmak daha iyidir.


Dosyaları regex ile aramak istiyorsanız , eşzamanlı olarak özyinelemeli dosya araması yapan file-regex kitaplığını kullanın .
Akash Babu

Yanıtlar:


92

node.js, özyinelemeli basit işlev:

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

Süslü olmak istiyorsanız RegExp'i ve onu genel hale getirmek için bir geri arama ekleyin.

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

demo kodu için çok teşekkürler! Kodunuzun üstüne bir şey ekledim ve harika çalışıyor! LiteScript projenizi de kontrol ettim ve harika. Github'da yıldız ekledim!
Nicolas S.Xu

Uzantısı olmayan dosya adlarını bulmak için güzel küçük bir komut dosyası - benim durumumda bazı Jpeg'lerim vardı ve farklı bir dizindeki orijinal dosyanın png veya jpeg olup olmadığını bulmam gerekiyordu, bu yardımcı oluyor
Ricky Odin Matthews

80

glob paketini kullanmayı seviyorum :

const glob = require('glob');

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

1
Normalde basit şeyler için bir paket hayranı değildir, ancak glob'un yerleşik bir js düğümüne sahip olması an meselesidir. Bu, dosya seçiminin bir tür normal ifadesi haline geliyor.
Seph Reed

27

Ne, bekle ?! ... Tamam ya, belki bu başkaları için de daha mantıklı geliyor.

[ nodejs 7 size dikkat edin]

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

Normal ifadeyle ne yaparsanız yapın, işlevde ayarladığınız bir bağımsız değişken yapın, varsayılan vb.


2
Bu sadece kök dizindeki eşleşen dosyaları alacaktır.
dreamerkumar

6
Düzenlemeye çalıştım ve reddedildim ki buna katılmıyorum. İşte önerim: stackoverflow.com/review/suggested-edits/19188733 her wl ne olursa olsun çok mantıklı. Ayrıca fs için içe aktarma eksik. İhtiyacınız olan üç satır: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Avindra Goolcharan

doğru üzgünüm wl.fs, fs kitaplığını içe aktarma yoluyla depoladığım yer.
Master James

oh içe aktarma muhtemelen şimdilik ihtiyaç duyulmasını gerektiren kendi özel işlevimdir, bu yüzden kesinlikle kullanım gerektirir veya ne yapmanız gerekiyorsa onu gerektirir.
Master James

13

Lucio'nun koduna göre bir modül yaptım. Birinin altında belirli uzantılara sahip tüm dosyalar ile bir geri dönecektir. Birinin ihtiyacı olursa diye buraya postalayın.

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

Bunu yapmak için Filehound'u kullanabilirsiniz .

Örneğin: tüm .html dosyalarını / tmp içinde bulun:

const Filehound = require('filehound');

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

    console.log(htmlFiles);
});

Daha fazla bilgi (ve örnekler) için dokümanlara bakın: https://github.com/nspragg/filehound

Feragatname : Yazar benim.


8

Yukarıdaki cevaplara baktım ve benim için çalışan bu versiyonu karıştırdım:

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

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

Bu test, yoldaki klasörde bulunan dosyalardan bir dizi dosya adı döndürecektir ./testdata. Düğüm sürümü 8.11.3 üzerinde çalışıyor.


1
RegExp'in sonuna $ eklerdim:.*\.(${extension})$
Eugene

3

Bunun için OS yardımını kullanabilirsiniz. İşte çapraz platform çözümü:

1. Aşağıdaki işlevi kullanır lsve diryinelemeli olarak arama yapmaz, ancak göreceli yolları vardır

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. Aşağıdaki işlev, findve kullanır dir, yinelemeli olarak arar, ancak pencerelerde mutlak yollara sahiptir

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
Bu şekilde yapılabileceğini hiç düşünmemiştim, çünkü gereksinimle ('child_process'). Teşekkür ederim!
Nicolas S.Xu

2
Bunu "nodejs kullanarak" yapmanın yolu bu değildir. Bu, işletim sistemini kullanıyor, başka bir işlemi başlatıyor vb. ".Html" ile biten bir dizin varsa da başarısız olur, örneğin: files.html /
Lucio M.

@ LucioM.Tato, arama yaparken dosya türünü belirtebilirsiniz. Bir problemin birçok çözümü vardır, eğer biri fikrinize uymuyorsa, bu sadece yanlış olduğu anlamına gelmez, sadece farklıdır. Bu cevap, hangi komut dosyası dili kullanılırsa kullanılsın, mevcut çözümleri yeniden kullanabileceğinizi kanıtlar.
Emil Condrea

Elbette, bir dizini yinelemek ve belirli uzantılara sahip dosyaları bulmakta yanlış bir şey yok, ancak işletim sisteminden tüm bu bilgileri almak istedim çünkü yapabileceğini biliyordum. :)
Emil Condrea

@EmilCondrea, IHMO bu, OP'nin sorduğu gibi "düğümü kullanmıyor". Her neyse, eğer seni rahatsız ediyorsa, olumsuz oyu kaldırırım.
Lucio M. Tato

3

Aşağıdaki kod ./ içinde özyinelemeli bir arama yapar (uygun şekilde değiştirin) ve .html ile biten mutlak dosya adları dizisi döndürür.

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

Dosya normal ifadesine bir göz atın

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

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

Yukarıdaki kod parçası js, geçerli dizindeki tüm dosyaları yazdırır .


Aslında oradaki en kolay çözüm bu.
kyeno

2

İtibar nedeniyle yorum eklenemiyor, ancak aşağıdakilere dikkat edin:

Fs.readdir veya node-glob dosyalarının 500.000 dosyalık bir klasördeki joker karakter kümesini bulmak için kullanılması yaklaşık 2 saniye sürdü. DIR ile exec kullanmak ~ 0,05s (özyinelemesiz) veya ~ 0,45s (özyinelemeli) aldı. (Tek bir dizinde kalıbımla eşleşen ~ 14 dosya arıyordum).

Şimdiye kadar, verimlilik için arama yapan düşük seviyeli işletim sistemi jokerini kullanan herhangi bir nodejs uygulaması bulamadım. Ancak yukarıdaki DIR / ls tabanlı kod, verimlilik açısından pencerelerde harika çalışıyor. ancak linux bulma, büyük dizinler için muhtemelen çok yavaş olacaktır .


Gerçekten ilginç.
philk

Not En son nodejs fs modülünde yeni işlevler olduğunu görüyorum (12.13+? Yinelenen dizin fns?). Henüz denemedim çünkü şimdilik 6.9.11'de takılı kaldım; bunun için herhangi bir yeni kullanışlı özellik sağlayıp sağlamadıklarını görmek ilginç olacaktır. Şimdi gönderimi düşünüyorum; İşletim sistemi önbelleğe alma da dikkate alınmalıdır. 0.05'lerim muhtemelen birkaç kez çalıştırdıktan SONRA ölçülürdü. İLK 'DIR' hızının ne olduğunu merak ediyorum?
Simon H

1

iki pensim, for döngüsü yerine harita kullanıyorum

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

Az önce fark ettim ki, uygulamanızı engelleyebilecek sync fs yöntemlerini kullanıyorsunuz, işte async ve q kullanarak söze dayalı eşzamansız bir yol , START = / myfolder FILTER = ". Jpg" node myfile.js ile çalıştırabilirsiniz, Aşağıdaki kodu myfile.js adlı bir dosyaya koyduğunuzu varsayarsak:

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
Geri arama cehenneminin harika bir örneği! :)
Afshin Moazami

2
haklısın, bunu bir daha yapmazdım: D Belki önümüzdeki günlerde zaman bulabilirim, asenkron ile çözerim / farkı göstermeyi beklerim.
Christoph Johannsdotter

0

Yüklemek

bu paketi kurabilirsin walk-sync'i :

yarn add walk-sync

Kullanım

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

-2

Eski gönderi ancak ES6 artık bunu includesyöntemle kutudan çıkarıyor .

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

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

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

Bunu, file.readdirSyncuzantıya göre filtrelemek için basit bir yol kullandığım ve ihtiyacım olduğu için yükselteceğim . Sanırım bu, bu konudaki sorunun bir kısmını yanıtlıyor ama belki her şeyi değil. Hala dikkate değer.
justinpage
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.