знайти файли за розширенням * .html у папці на nodejs


90

Я хотів би знайти всі файли * .html у папці src та всі її підпапки за допомогою nodejs. Який найкращий спосіб це зробити?

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

Я думаю, що багато розробників повинні мати чудове і перевірене рішення, і краще використовувати його, ніж писати його самостійно.


Якщо ви хочете шукати файли за регулярними виразами, використовуйте бібліотеку регулярних виразів , яка виконує рекурсивний пошук файлів одночасно.
Акаш Бабу

Відповіді:


91

node.js, рекурсивна проста функція:

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

додайте RegExp, якщо хочете захопитись, і зворотний дзвінок, щоб зробити його загальним.

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

велике спасибі за демо-код! Я додав щось поверх вашого коду, і це чудово працює! Я також перевірив ваш проект LiteScript, і це дивно. Я позначив це на github!
Nicolas S.Xu

Хороший маленький скрипт для пошуку імен файлів без розширення - у моєму випадку у мене було кілька файлів JPEG і мені потрібно було знайти, чи був оригінальний файл в іншому каталозі png або jpeg, це допомагає
Рікі Одін Метьюз

78

мені подобається використовувати пакет glob :

const glob = require('glob');

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

1
Зазвичай не є шанувальником пакетів для простих речей, але це лише питання часу, коли glob має вбудовану реалізацію node js. Це свого роду стає регулярним виразом вибору файлу.
Seph Reed,

27

Що, тримайся ?! ... Добре, може, це також має сенс для когось іншого.

[ nodejs 7 зауважте]

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

Робіть все, що стосується регулярного виразу, робіть це аргументом, який ви встановили у функції із типовим значенням тощо.


2
Це дозволить отримати лише відповідні файли в кореневому каталозі.
dreamerkumar

6
Я намагався редагувати, і мене відхилили, з чим я не погоджуюсь. Ось моя пропозиція: stackoverflow.com/review/suggest-edits/19188733 wl має такий сенс. Також відсутній імпорт для fs. Три лінії, які вам потрібні: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Авіндра Гулчаран

правильно, вибачте, wl.fs - це місце, де я зберігав fs lib за допомогою імпорту.
Майстер Джеймс

о імпорт - це, мабуть, моя власна спеціальна функція, яка наразі вказує на необхідність, тому переконайтеся, що використання вимагає або що вам потрібно зробити.
Майстер Джеймс

13

На основі коду Люсіо я зробив модуль. Він поверне всі файли зі спеціальними розширеннями під одним. Просто опублікуйте його тут, якщо комусь це буде потрібно.

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

Ви можете використовувати Filehound для цього.

Наприклад: знайти всі файли .html у / 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);
});

Для отримання додаткової інформації (та прикладів) перегляньте документи: https://github.com/nspragg/filehound

Застереження : Я автор.


8

Я розглянув наведені вище відповіді та змішав цю версію, яка мені підходить:

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

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

Цей тест поверне масив імен файлів із файлів, знайдених у папці на шляху ./testdata. Робота над версією версії 8.11.3.


1
Я додав би $ в кінці RegExp:.*\.(${extension})$
Євген

3

Для цього ви можете скористатися довідкою ОС. Ось крос-платформне рішення:

1. Функція нижче використовує lsі dirне шукає рекурсивно, але вона має відносні шляхи

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. Функція нижче використовує findі dir, шукає рекурсивно, але у вікнах вона має абсолютні шляхи

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
Я ніколи не думав, що це можна зробити таким чином, оскільки я не знайомий з require ('child_process'). Exec, але це виглядає дуже добре і вселяє в мене багато думок. Дякую!
Nicolas S.Xu

2
Це не спосіб зробити це "за допомогою nodejs". Це використання ОС, запуск іншого процесу тощо. Це також не вдається, якщо є папка, що закінчується на ".html", наприклад: files.html /
Lucio M. Tato

@ LucioM. Щоб вказати тип файлу під час пошуку. Існує багато рішень проблеми, якщо хтось не відповідає вашій ідеї, це просто не означає, що він помилковий, це просто інше. Ця відповідь доводить, що ви можете повторно використовувати існуючі рішення незалежно від того, яка мова сценаріїв використовується.
Emil Condrea

Звичайно, це нічого поганого в перегляді каталогу і пошуку файлів з певним розширенням, але я просто хотів отримати від ОС всю цю інформацію, бо знав, що він може це зробити. :)
Emil Condrea

@EmilCondrea, IHMO це не "використовує вузол", як просив ОП. У будь-якому разі я зніму голос проти, якщо це вас турбує.
Lucio M. Tato

3

Наступний код робить рекурсивний пошук всередині ./ (змінити його відповідним чином) і повертає масив абсолютних імен файлів, що закінчуються на .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

Не вдається додати коментар через репутацію, але зверніть увагу на таке:

Використання fs.readdir або node-glob для пошуку набору символів підстановки у папці з 500 000 файлів зайняло ~ 2 с. Використання exec з DIR займало ~ 0,05 с (нерекурсивно) або ~ 0,45 с (рекурсивно). (Я шукав ~ 14 файлів, що відповідають моєму шаблону, в одному каталозі).

Наразі мені не вдалося знайти жодної реалізації nodejs, яка використовує низький рівень підстановки ОС для пошуку ефективності. Але вищезазначений код на основі DIR / ls чудово працює у вікнах з точки зору ефективності. linux find, однак, швидше за все, буде дуже повільним для великих каталогів.


Цікаво, справді.
philk

Примітка. Я бачу, що в останньому модулі nodejs fs (12.13+ - ітераційний каталог fns?) Є нові функції. Я ще не пробував їх, бо поки що застряг на 6.9.11; буде цікаво подивитися, чи надають вони якісь нові корисні функції для цього. Думаючи про мій пост зараз; Також слід враховувати кешування ОС. Мої 0,05 с, швидше за все, були б виміряні ПІСЛЯ того, як пропустити їх кілька разів. Цікаво, якою є ПЕРША швидкість "DIR"?
Саймон Н

1

мої два пенси, використовуючи карту замість 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);

1

Погляньте на файл-регулярний вираз

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

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

Цей наведений вище фрагмент надрукує всі jsфайли в поточному каталозі.


Це насправді найпростіше рішення.
kyeno

0

Я щойно помітив, ви використовуєте синхронізуючі fs-методи, які можуть заблокувати вашу програму, ось асинхронний спосіб на основі обіцянок за допомогою async та q , ви можете виконати його за допомогою START = / myfolder FILTER = ". Jpg" node myfile.js, якщо припустити, що ви помістили наступний код у файл 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
Прекрасний приклад пекло зворотного дзвінка! :)
Афшин Моазамі

2
ти маєш рацію, не робив би цього ще раз: D Можливо, я знайду час наступних днів, вирішивши це за допомогою async / await, щоб показати різницю.
Крістоф Йоганнсдоттер


-2

Старий пост, але ES6 тепер обробляє це нестандартно includesметодом.

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

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

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

Збираюся проголосувати за це, тому що я використовував file.readdirSync і потрібен був простий спосіб відфільтрувати файли за розширенням. Я думаю, це відповідає на частину запитання у цій темі, але, можливо, не на все. Все-таки варто розглянути.
justinpage
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.