tìm tệp theo phần mở rộng, * .html trong thư mục trong nodejs


90

Tôi muốn tìm tất cả các tệp * .html trong thư mục src và tất cả các thư mục con của nó bằng cách sử dụng nodejs. Cách tốt nhất để làm điều đó là gì?

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

Tôi nghĩ rằng nhiều nhà phát triển nên có giải pháp tuyệt vời và đã được thử nghiệm và tốt hơn là sử dụng nó hơn là tự viết một giải pháp.


Nếu bạn muốn tìm kiếm tệp bằng regex, thì hãy sử dụng thư viện tệp-regex , thư viện này thực hiện tìm kiếm tệp đệ quy đồng thời.
Akash Babu

Câu trả lời:


91

node.js, hàm đơn giản đệ quy:

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

thêm RegExp nếu bạn muốn trở nên lạ mắt và gọi lại để làm cho nó chung chung.

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

cảm ơn rất nhiều cho mã demo! Tôi đã thêm một cái gì đó vào đầu mã của bạn và nó hoạt động tuyệt vời! Tôi cũng đã kiểm tra dự án LiteScript của bạn, và nó thật tuyệt vời. Tôi đã gắn dấu sao nó trên github!
Nicolas S.Xu

Ít kịch bản tốt đẹp cho việc tìm kiếm tên tập tin mà không cần mở rộng cũng - trong trường hợp của tôi, tôi đã có một số hình ảnh JPEG và cần thiết để tìm thấy nếu các tập tin gốc trong một thư mục khác nhau được png hoặc jpeg, điều này giúp
Ricky Odin Matthews

78

tôi thích sử dụng gói cầu :

const glob = require('glob');

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

1
Thông thường không phải là một fan hâm mộ của các gói cho những thứ đơn giản, nhưng chỉ là vấn đề thời gian trước khi global có triển khai nút js tích hợp sẵn. Đây là loại trở thành regexp của lựa chọn tệp.
Reed

27

Cái gì, chờ đã ?! ... Được rồi, có lẽ điều này cũng có ý nghĩa hơn đối với một số người khác.

[ nodejs 7 nhớ bạn]

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

Làm bất cứ điều gì với regex khiến nó trở thành đối số bạn đặt trong hàm với mặc định, v.v.


2
Điều này sẽ chỉ nhận được các tệp phù hợp trong thư mục gốc.
dreamerkumar

6
Tôi đã cố gắng chỉnh sửa và bị từ chối, điều mà tôi không đồng ý. Đây là đề xuất của tôi: stackoverflow.com/review/suggested-edits/19188733 wl rất hợp lý. Ngoài ra, nhập cho fs bị thiếu. Ba dòng bạn cần là: 1. const fs = require('fs');2. const dirCont = fs.readdirSync( dir );3.const files = dirCont.filter( ( elm ) => /.*\.(htm?html)/gi.test(elm) );
Avindra Goolcharan.

xin lỗi wl.fs là nơi tôi lưu trữ fs lib thông qua nhập khẩu.
Master James

oh nhập khẩu có lẽ là chức năng tùy chỉnh của riêng tôi mà bây giờ cũng cần phải có vì vậy chắc chắn việc sử dụng yêu cầu hoặc bất cứ điều gì bạn phải làm.
Master James

13

Dựa trên mã của Lucio, tôi đã tạo một mô-đun. Nó sẽ trả lại tất cả các tệp có phần mở rộng cụ thể bên dưới. Chỉ cần đăng nó ở đây trong trường hợp bất kỳ ai cần 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

Bạn có thể sử dụng Filehound để làm điều này.

Ví dụ: tìm tất cả các tệp .html trong / 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);
});

Để biết thêm thông tin (và ví dụ), hãy xem tài liệu: https://github.com/nspragg/filehound

Disclaimer : Tôi là tác giả.


8

Tôi đã xem xét các câu trả lời ở trên và đã kết hợp với nhau phiên bản này phù hợp với tôi:

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

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

Kiểm tra này sẽ trả về một mảng tên tệp từ các tệp được tìm thấy trong thư mục ở đường dẫn ./testdata. Làm việc trên phiên bản nút 8.11.3.


1
Tôi sẽ thêm $ vào cuối RegExp:.*\.(${extension})$
Eugene

3

Bạn có thể sử dụng trợ giúp của hệ điều hành cho việc này. Đây là một giải pháp đa nền tảng:

1. Hàm dưới đây sử dụng lsdirkhông tìm kiếm đệ quy nhưng nó có các đường dẫn tương đối

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. Hàm dưới đây sử dụng finddirtìm kiếm đệ quy nhưng trên windows nó có đường dẫn tuyệt đối

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
Tôi chưa bao giờ nghĩ rằng nó có thể được thực hiện theo cách này, vì tôi không quen thuộc với lệnh request ('child_process'). Executive, nhưng nó trông rất hay và khơi gợi rất nhiều suy nghĩ trong tôi. Cảm ơn bạn!
Nicolas S.Xu

2
Đây không phải là cách để làm điều đó "sử dụng nodejs". Này được sử dụng hệ điều hành, triển khai quá trình khác, vv Nó cũng thất bại nếu có một dir kết thúc bằng ".html", ví dụ như: files.html /
Lucio M. Tato

@ LucioM.Tato bạn cand chỉ định loại tệp khi tìm kiếm. Có rất nhiều giải pháp cho một vấn đề, nếu một giải pháp không phù hợp với ý tưởng của bạn thì không có nghĩa là nó sai, nó chỉ là khác biệt. Câu trả lời này chứng minh rằng bạn có thể sử dụng lại các giải pháp hiện có cho dù ngôn ngữ script được sử dụng là gì.
Emil Condrea

Tất nhiên điều đó không có gì sai khi lặp lại một thư mục và tìm các tệp có phần mở rộng nhất định nhưng tôi chỉ muốn nhận từ HĐH tất cả thông tin này vì tôi biết anh ấy có thể làm được. :)
Emil Condrea

@EmilCondrea, IHMO đây không phải là "sử dụng nút" như OP yêu cầu. Dù sao, tôi sẽ xóa phiếu phản đối nếu điều đó làm phiền bạn.
Lucio M. Tato

3

Đoạn mã sau thực hiện tìm kiếm đệ quy bên trong ./ (thay đổi nó một cách thích hợp) và trả về một mảng tên tệp tuyệt đối kết thúc bằng .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

Không thể thêm nhận xét vì danh tiếng, nhưng hãy lưu ý những điều sau:

Sử dụng fs.readdir hoặc node-global để tìm một tập hợp ký tự đại diện của các tệp trong một thư mục 500.000 tệp mất khoảng 2 giây. Sử dụng thực thi với DIR mất ~ 0,05 giây (không đệ quy) hoặc ~ 0,45 giây (đệ quy). (Tôi đang tìm kiếm ~ 14 tệp phù hợp với mẫu của tôi trong một thư mục).

Cho đến nay, tôi đã không tìm thấy bất kỳ triển khai nodejs nào sử dụng tìm kiếm ký tự đại diện hệ điều hành cấp thấp để có hiệu quả. Nhưng mã dựa trên DIR / ls ở trên hoạt động tuyệt vời trong windows về mặt hiệu quả. Tuy nhiên, tìm kiếm linux có thể sẽ rất chậm đối với các thư mục lớn.


Thật thú vị.
philk

Lưu ý rằng tôi thấy có các chức năng mới trong mô-đun nodejs fs mới nhất (12.13+? Thư mục lặp fns?). Tôi vẫn chưa thử chúng vì hiện tại tôi đang bị mắc kẹt trên 6.9.11; sẽ rất thú vị để xem liệu họ có cung cấp bất kỳ tính năng hữu ích mới nào cho việc này hay không. Suy nghĩ về bài viết của tôi bây giờ; Bộ nhớ đệm hệ điều hành cũng nên được xem xét. 0,05s của tôi có thể đã được đo SAU KHI chạy nó một số lần. Tôi tự hỏi tốc độ 'DIR' ĐẦU TIÊN là bao nhiêu?
Simon H

1

hai pence của tôi, sử dụng bản đồ thay cho vòng lặp

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

Hãy xem xét tệp-regex

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

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

Đoạn mã trên sẽ in tất cả các jstệp trong thư mục hiện tại.


Đó thực sự là giải pháp dễ dàng nhất hiện có.
kyeno

0

Tôi chỉ nhận thấy rằng, bạn đang sử dụng các phương thức fs đồng bộ, có thể chặn ứng dụng của bạn, đây là cách không đồng bộ dựa trên lời hứa sử dụng asyncq , bạn có thể thực thi nó với nút START = / myfolder FILTER = ". Jpg" myfile.js, giả sử bạn đặt mã sau vào tệp có tên 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
Một ví dụ tuyệt vời về địa ngục gọi lại! :)
Afshin Moazami

2
bạn đúng, sẽ không làm theo cách này nữa: D Có lẽ tôi sẽ tìm thấy thời gian vào những ngày tiếp theo, giải quyết nó với async / await để cho thấy sự khác biệt.
Christoph Johannsdotter

0

Tải về

bạn có thể cài đặt walk-sync gói này bằng cách

yarn add walk-sync

Sử dụng

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

-2

Bài cũ nhưng ES6 hiện xử lý điều này ra khỏi hộp bằng includesphương pháp này.

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

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

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

Tôi sẽ ủng hộ điều này vì tôi đang sử dụng file.readdirSyncvà cần một cách đơn giản để lọc ra các tệp theo phần mở rộng. Tôi nghĩ rằng điều này trả lời một phần của câu hỏi trong chủ đề này nhưng có lẽ không phải là tất cả. Vẫn đáng xem xét.
justinpage
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.