temukan file dengan ekstensi, * .html di bawah folder di nodejs

92

Saya ingin menemukan semua file * .html di folder src dan semua sub foldernya menggunakan nodejs. Apa cara terbaik untuk melakukannya?

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

Saya pikir banyak pengembang harus memiliki solusi yang hebat dan teruji dan lebih baik menggunakannya daripada menulis sendiri.

Nicolas S.Xu
sumber
Jika Anda ingin mencari file dengan regex, gunakan library file-regex , yang melakukan pencarian file secara rekursif secara bersamaan.
Akash Babu

Jawaban:

92

node.js, fungsi sederhana rekursif:

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

tambahkan RegExp jika Anda ingin terlihat keren, dan panggil balik untuk membuatnya umum.

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);
});
Lucio M. Tato
sumber
terima kasih banyak untuk kode demo! Saya menambahkan sesuatu di atas kode Anda dan berfungsi dengan baik! Saya juga memeriksa proyek LiteScript Anda, dan itu luar biasa. Saya telah membintanginya di github!
Nicolas S.Xu
Skrip kecil yang bagus untuk menemukan nama file tanpa ekstensi juga - dalam kasus saya, saya memiliki beberapa Jpeg dan perlu menemukan apakah file asli di direktori yang berbeda adalah png atau jpeg, ini membantu
Ricky Odin Matthews
80

saya suka menggunakan paket glob :

const glob = require('glob');

glob(__dirname + '/**/*.html', {}, (err, files)=>{
  console.log(files)
})
David Cheung
sumber
1
Biasanya bukan penggemar paket untuk hal-hal sederhana, tetapi hanya masalah waktu sebelum glob memiliki implementasi node js bawaan. Ini semacam menjadi regexp dari pemilihan file.
Seph Reed
27

Apa, tunggu ?! ... Oke ya, mungkin ini lebih masuk akal bagi orang lain juga.

[ nodejs 7 ingatlah]

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

Lakukan apa pun dengan regex menjadikannya argumen yang Anda tetapkan dalam fungsi dengan default, dll.

Tuan James
sumber
2
Ini hanya akan mendapatkan file yang cocok di direktori root.
dreamerkumar
6
Saya mencoba mengedit dan ditolak, yang tidak saya setujui. Ini proposal saya: stackoverflow.com/review/suggested-edits/19188733 wl sangat masuk akal. Impor untuk fs juga hilang. Tiga baris yang Anda butuhkan adalah: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Avindra Goolcharan
benar maaf wl.fs adalah tempat saya menyimpan fs lib melalui import.
Tuan James
oh impor mungkin adalah fungsi kustom saya sendiri yang menunjukkan perlu untuk saat ini juga jadi pastikan penggunaan memerlukan atau apa pun yang harus Anda lakukan.
Tuan James
13

Berdasarkan kode Lucio, saya membuat modul. Ini akan mengembalikan semua file dengan ekstensi tertentu di bawahnya. Cukup posting di sini jika ada yang membutuhkannya.

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;
Nicolas S.Xu
sumber
12

Anda dapat menggunakan Filehound untuk melakukan ini.

Misalnya: temukan semua file .html di / 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);
});

Untuk informasi lebih lanjut (dan contoh), lihat dokumen: https://github.com/nspragg/filehound

Penafian : Saya adalah penulisnya.

nickool
sumber
8

Saya telah melihat jawaban di atas dan telah menggabungkan versi ini yang bekerja untuk saya:

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

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

Tes ini akan mengembalikan larik nama file dari file yang ditemukan di folder di jalur ./testdata. Bekerja pada node versi 8.11.3.

Netsi1964
sumber
1
Saya akan menambahkan $ di akhir Ekspresi Reg:.*\.(${extension})$
Eugene
3

Anda dapat menggunakan bantuan OS untuk ini. Berikut adalah solusi lintas platform:

1. Fungsi di bawah ini menggunakan lsdan dirdan tidak mencari secara rekursif tetapi memiliki jalur relatif

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. Fungsi di bawah ini menggunakan finddan dir, mencari secara rekursif tetapi pada windows memiliki jalur absolut

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);
})
Emil Condrea
sumber
1
Saya tidak pernah berpikir itu bisa dilakukan dengan cara ini, karena saya tidak terbiasa dengan require ('child_process'). Exec, tetapi tampilannya sangat bagus dan menginspirasi banyak pemikiran dalam diri saya. Terima kasih!
Nicolas S.Xu
2
Ini bukan cara untuk melakukannya "menggunakan nodejs". Ini menggunakan OS, meluncurkan proses lain, dll. Ini juga gagal jika ada dir yang diakhiri dengan ".html", misalnya: files.html /
Lucio M. Tato
@ LucioM.Tato Anda dapat menentukan jenis file saat mencari. Ada banyak solusi untuk suatu masalah, jika salah satu tidak sesuai dengan ide Anda, itu tidak berarti salah, itu hanya berbeda. Jawaban ini membuktikan bahwa Anda dapat menggunakan kembali solusi yang ada apa pun bahasa skrip yang digunakan.
Emil Condrea
Tentu saja tidak ada yang salah dengan iterasi direktori dan mencari file dengan ekstensi tertentu tetapi saya hanya ingin menerima dari OS semua informasi ini karena saya tahu dia bisa melakukannya. :)
Emil Condrea
@EmilCondrea, IHMO ini tidak "menggunakan node" seperti yang diminta OP. Bagaimanapun saya akan menghapus suara negatif jika itu mengganggu Anda.
Lucio M. Tato
3

Kode berikut melakukan pencarian rekursif di dalam ./ (mengubahnya dengan benar) dan mengembalikan larik nama file absolut yang diakhiri dengan .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);
Nikhil
sumber
2

Lihat file-regex

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

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

Potongan di atas akan mencetak semua jsfile di direktori saat ini.

Akash Babu
sumber
Itu sebenarnya solusi termudah di luar sana.
kyeno
2

Tidak dapat menambahkan komentar karena reputasi, tetapi perhatikan hal berikut:

Menggunakan fs.readdir atau node-glob untuk menemukan sekumpulan file wildcard dalam folder berisi 500.000 file membutuhkan waktu ~ 2s. Menggunakan exec dengan DIR membutuhkan waktu ~ 0,05 detik (non rekursif) atau ~ 0,45 detik (rekursif). (Saya sedang mencari ~ 14 file yang cocok dengan pola saya dalam satu direktori).

Sejauh ini, saya gagal menemukan implementasi nodejs yang menggunakan wildcard OS tingkat rendah untuk mencari efisiensi. Tetapi kode berbasis DIR / ls di atas bekerja dengan sangat baik di windows dalam hal efisiensi. linux menemukan, bagaimanapun, kemungkinan akan sangat lambat untuk direktori besar.

Simon H.
sumber
Menarik, memang.
philk
Catatan Saya melihat ada fungsi baru di modul nodejs fs terbaru (12.13+? Direktori iterated fns?). Saya belum mencobanya karena saya terjebak pada 6.9.11 untuk saat ini; akan menarik untuk melihat apakah mereka menyediakan fitur berguna baru untuk ini. Berpikir tentang posting saya sekarang; Caching OS juga harus dipertimbangkan. 0,05 saya kemungkinan besar akan diukur SETELAH menjalankannya beberapa kali. Aku ingin tahu apa kecepatan 'DIR' PERTAMA?
Simon H
1

dua pence saya, menggunakan peta sebagai pengganti 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);
jset74
sumber
0

Saya baru saja memperhatikan, Anda menggunakan metode sinkronisasi fs, yang mungkin memblokir aplikasi Anda, berikut adalah cara asinkron berbasis janji menggunakan async dan q , Anda dapat menjalankannya dengan START = / myfolder FILTER = ". Jpg" node myfile.js, dengan asumsi Anda meletakkan kode berikut dalam file bernama 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);
})
Christoph Johannsdotter
sumber
4
Contoh yang bagus dari callback hell! :)
Afshin Moazami
2
Anda benar, tidak akan melakukannya dengan cara ini lagi: D Mungkin saya akan menemukan waktu hari-hari berikutnya, menyelesaikannya dengan async / menunggu untuk menunjukkan perbedaannya.
Christoph Johannsdotter
0

Install

Anda dapat menginstal paket ini berjalan-sync oleh

yarn add walk-sync

Pemakaian

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

Posting lama tetapi ES6 sekarang menangani ini di luar kotak dengan includesmetode.

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

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

console.log("Files: ", jsonFiles) ==> //file.json
James
sumber
Akan meningkatkan ini karena saya menggunakan file.readdirSyncdan membutuhkan cara sederhana untuk memfilter file dengan ekstensi. Saya pikir ini menjawab sebagian dari pertanyaan di utas ini, tetapi mungkin tidak semuanya. Masih layak dipertimbangkan.
justinpage