नोड .js fs.readdir पुनरावर्ती निर्देशिका खोज


267

एक async निर्देशिका पर कोई विचार fs.readdir का उपयोग कर खोज? मुझे लगता है कि हम पुनरावृत्ति का परिचय दे सकते हैं और पढ़ने के लिए अगली निर्देशिका के साथ रीड डायरेक्टरी फ़ंक्शन को कॉल कर सकते हैं, लेकिन इसके बारे में थोड़ा चिंतित हैं क्योंकि यह अनिवार्य नहीं है ...

कोई विचार? मैंने नोड-वॉक पर ध्यान दिया है जो बहुत अच्छा है, लेकिन मुझे सिर्फ एक सरणी में फाइल नहीं देता है, जैसे कि रीडिर करता है। हालांकि

जैसे आउटपुट की तलाश ...

['file1.txt', 'file2.txt', 'dir/file3.txt']

जवाबों:


379

इसे पूरा करने के मूल रूप से दो तरीके हैं। एक async वातावरण में आप देखेंगे कि दो प्रकार के लूप हैं: धारावाहिक और समानांतर। एक सीरियल लूप अगली पुनरावृत्ति पर जाने से पहले एक पुनरावृत्ति को पूरा करने की प्रतीक्षा करता है - यह गारंटी देता है कि लूप का प्रत्येक पुनरावृत्ति क्रम में पूरा होता है। एक समानांतर लूप में, सभी पुनरावृत्तियों को एक ही समय में शुरू किया जाता है, और एक दूसरे से पहले पूरा हो सकता है, हालांकि, यह एक सीरियल लूप की तुलना में बहुत तेज है। तो इस मामले में, संभवतः एक समानांतर लूप का उपयोग करना बेहतर होता है क्योंकि इससे कोई फर्क नहीं पड़ता कि चलना किस क्रम में पूरा होता है, जब तक यह पूरा होता है और परिणाम लौटाता है (जब तक आप उन्हें क्रम में नहीं चाहते)।

एक समानांतर लूप इस तरह दिखेगा:

var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
  var results = [];
  fs.readdir(dir, function(err, list) {
    if (err) return done(err);
    var pending = list.length;
    if (!pending) return done(null, results);
    list.forEach(function(file) {
      file = path.resolve(dir, file);
      fs.stat(file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          walk(file, function(err, res) {
            results = results.concat(res);
            if (!--pending) done(null, results);
          });
        } else {
          results.push(file);
          if (!--pending) done(null, results);
        }
      });
    });
  });
};

एक सीरियल लूप इस तरह दिखेगा:

var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
  var results = [];
  fs.readdir(dir, function(err, list) {
    if (err) return done(err);
    var i = 0;
    (function next() {
      var file = list[i++];
      if (!file) return done(null, results);
      file = path.resolve(dir, file);
      fs.stat(file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          walk(file, function(err, res) {
            results = results.concat(res);
            next();
          });
        } else {
          results.push(file);
          next();
        }
      });
    })();
  });
};

और इसे अपने घर निर्देशिका पर परीक्षण करने के लिए (चेतावनी: यदि आपकी गृह निर्देशिका में बहुत अधिक सामान है तो परिणाम सूची बहुत बड़ी होगी):

walk(process.env.HOME, function(err, results) {
  if (err) throw err;
  console.log(results);
});

संपादित करें: बेहतर उदाहरण।


10
खबरदार, ऊपर के chjj से "समानांतर लूप" उत्तर में मामलों में बग है जब एक खाली फ़ोल्डर चलता है। फिक्स है: var लंबित = list.length; अगर (लंबित) किया गया है (अशक्त, परिणाम); // इस लाइन को जोड़ें! list.forEach (फंक्शन (फ़ाइल) {...
वासिल डस्कालोपोलोस

27
file = dir + '/' + file;यह अनुशंसित नहीं है। आप का उपयोग करना चाहिए:var path = require('path'); file = path.resolve(dir, file);
लीको

7
@onetrickpony क्योंकि अगर आप उपयोग करते path.resolve(...)हैं तो आपको एक उचित रास्ता मिलेगा कि क्या आप विंडोज या यूनिक्स पर हैं :) इसका मतलब है कि आपको C:\\some\\foo\\pathविंडोज /some/foo/pathपर और यूनिक्स सिस्टम पर कुछ मिलेगा
लेइको

19
मैंने यह अस्वीकार कर दिया क्योंकि आपका जवाब बहुत अच्छा था जब आपने पहली बार इसे 2011 में वापस लिखा था, लेकिन 2014 में लोग खुले स्रोत मॉड्यूल का उपयोग करते हैं और स्वयं कम कोड लिखते हैं और उन मॉड्यूल में योगदान करते हैं जो वे और इतने सारे अन्य लोग निर्भर करते हैं। उदाहरण के लिए नोड- dir को कोड की इस लाइन का उपयोग करके @crawf द्वारा आवश्यक आउटपुट प्राप्त करने का प्रयास करें:require('node-dir').files(__dirname, function(err, files) { console.log(files); });
क्रिस्टियान

5
!--वाक्य रचना के बारे में भ्रमित किसी के लिए, इसके बारे में एक प्रश्न पूछा गया है
Tas

145

यह एक नोड 8 में उपलब्ध अधिकतम, नए, buzzwordy फीचर्स का उपयोग करता है, जिसमें प्रॉमिस, उपयोग / प्रॉमिस, डिस्ट्रक्टिंग, एसिंक्स-वेट, मैप + कम और अधिक शामिल हैं, जिससे आपके सहकर्मी अपने सिर को खरोंच कर सकते हैं क्योंकि वे यह पता लगाने की कोशिश करते हैं कि क्या चल रहा है।

नोड 8+

कोई बाहरी निर्भरता नहीं।

const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

async function getFiles(dir) {
  const subdirs = await readdir(dir);
  const files = await Promise.all(subdirs.map(async (subdir) => {
    const res = resolve(dir, subdir);
    return (await stat(res)).isDirectory() ? getFiles(res) : res;
  }));
  return files.reduce((a, f) => a.concat(f), []);
}

प्रयोग

getFiles(__dirname)
  .then(files => console.log(files))
  .catch(e => console.error(e));

नोड 10.10+

नोड 10+ के लिए अद्यतन और भी अधिक whizbang के साथ:

const { resolve } = require('path');
const { readdir } = require('fs').promises;

async function getFiles(dir) {
  const dirents = await readdir(dir, { withFileTypes: true });
  const files = await Promise.all(dirents.map((dirent) => {
    const res = resolve(dir, dirent.name);
    return dirent.isDirectory() ? getFiles(res) : res;
  }));
  return Array.prototype.concat(...files);
}

ध्यान दें कि नोड 11.15.0 से शुरू होकर आप फाइल ऐरे को समतल करने के files.flat()बजाय उपयोग कर सकते हैं Array.prototype.concat(...files)

नोड 11+

यदि आप हर किसी के सिर को पूरी तरह से उड़ाना चाहते हैं, तो आप निम्न संस्करण का उपयोग कर सकते हैं async पुनरावृत्तियों का उपयोग कर । वास्तव में शांत होने के अलावा, यह उपभोक्ताओं को एक बार में परिणाम निकालने की अनुमति देता है, जिससे यह वास्तव में बड़ी निर्देशिकाओं के लिए बेहतर अनुकूल हो जाता है।

const { resolve } = require('path');
const { readdir } = require('fs').promises;

async function* getFiles(dir) {
  const dirents = await readdir(dir, { withFileTypes: true });
  for (const dirent of dirents) {
    const res = resolve(dir, dirent.name);
    if (dirent.isDirectory()) {
      yield* getFiles(res);
    } else {
      yield res;
    }
  }
}

उपयोग बदल गया है क्योंकि वापसी प्रकार अब एक वादा के बजाय एक async पुनरावृत्ति है

(async () => {
  for await (const f of getFiles('.')) {
    console.log(f);
  }
})()

अगर किसी को दिलचस्पी है, तो मैंने यहाँ async पुनरावृत्तियों के बारे में अधिक लिखा है: https://qwtel.com/posts/software/async-generators-in-the-wild/


5
के नामकरण subdirऔर subdirsभ्रामक है, उन वास्तव में फ़ाइलें हो सकता है के रूप में (मैं की तरह कुछ सुझाव है itemInDirया item_in_dirया यहाँ तक कि बस itemके बजाय।), लेकिन इस समाधान स्वीकार किए जाते हैं एक से क्लीनर लगता है और बहुत कम कोड है। मुझे स्वीकृत उत्तर में कोड की तुलना में यह अधिक जटिल नहीं लगता है। +1
ज़ेलफिर कल्टस्टाल

1
आप इसे और भी अधिक उपयोग करके पूरी तरह से require(fs).promisesगिरा सकते हैं util.promisify। व्यक्तिगत रूप से मैं उर्फ ​​एफएस को fs.promises।
मुशीननशीन

2
हम एक छोटे से बदलाव के साथ इसे और तेज़ कर सकते हैं: readdirAKA के लिए 2 तर्क को पास करना जैसे विकल्प ऑब्जेक्ट इसलिए कि readdir(dir, {withFileTypes: true})यह सभी प्रकारों को उनके प्रकार की जानकारी के साथ वापस कर देगा, इसलिए हमें अब statजो जानकारी मिलती है उसे प्राप्त करने के लिए readdirहमें कॉल करने की आवश्यकता नहीं होगी। वापस। यह हमें अतिरिक्त sys कॉल करने की आवश्यकता से बचाता है। यहाँ विवरण
cacoder

1
@cacoder को शामिल करने के लिए अद्यतन किया गया withFileTypes। पारितोषिक के लिए धन्यवाद।
qwtel

नोड 10.10+ में, यदि आप अपने return Array.prototype.concat(...files);साथ प्रतिस्थापित करते let result = Array.prototype.concat(...files); return result.map(file => file.split('\\').join('/'));हैं , तो सुनिश्चित करें कि dirs एक "/" लौटा सकते हैं और एक "\" नहीं। यदि आप regex बुरा नहीं मानते हैं, तो आप भी कर सकते हैंreturn result.map(file => file.replace(/\\/g, '/'));
SwiftNinjaPro

106

बस अगर किसी को यह उपयोगी लगता है, तो मैंने एक समकालिक संस्करण भी साथ रखा ।

var walk = function(dir) {
    var results = [];
    var list = fs.readdirSync(dir);
    list.forEach(function(file) {
        file = dir + '/' + file;
        var stat = fs.statSync(file);
        if (stat && stat.isDirectory()) { 
            /* Recurse into a subdirectory */
            results = results.concat(walk(file));
        } else { 
            /* Is a file */
            results.push(file);
        }
    });
    return results;
}

टिप: फ़िल्टर करते समय कम संसाधनों का उपयोग करने के लिए। इस फ़ंक्शन के भीतर ही फ़िल्टर करें। उदाहरण results.push(file);के लिए नीचे कोड के साथ बदलें । आवश्यकतानुसार समायोजित करें:

    file_type = file.split(".").pop();
    file_name = file.split(/(\\|\/)/g).pop();
    if (file_type == "json") results.push(file);

60
मुझे यह समाधान पसंद है, सिवाय इसके कि अर्ध-कॉलनों की कमी!
एमपीएन

यह सरल है। लेकिन थोड़ा सा भोला भी। यदि निर्देशिका में मूल निर्देशिका का लिंक है तो स्टैकओवरफ़्लो हो सकता है। शायद lstatइसके बजाय उपयोग करें ? या फिर पुनरावृत्ति स्तर को सीमित करने के लिए एक पुनरावर्ती जांच जोड़ें।
conradkleinespel

14
फ़ाइल का उपयोग करने पर विचार करें = आवश्यकता ("पथ")। join (dir, फ़ाइल)
mkamioner

16
@mpen Semi-colons निरर्थक हैं
सहयोगी

यह भी मेरे लिए सबसे अच्छा काम करता है। हालांकि मैंने एक विशिष्ट फ़ाइल एक्सटेंशन के लिए फ़िल्टर करने के लिए एक फिल्टर भी जोड़ा।
ब्रायन

87

A. फाइल मॉड्यूल पर एक नजर है । यह एक समारोह कहा जाता है:

file.walk (प्रारंभ, कॉलबैक)

एक फ़ाइल ट्री को नेविगेट करता है, प्रत्येक डायरेक्टरी के लिए कॉलबैक कहता है, (null, dirPath, dirs, files) में गुजरता है।

यह आपके लिए हो सकता है! और हाँ, यह async है। हालाँकि, मुझे लगता है कि आपको पूरे रास्ते को खुद बनाना होगा, अगर आपको उनकी ज़रूरत है।

बी एक विकल्प, और यहां तक ​​कि मेरे पसंदीदा में से एक: इसके लिए यूनिक्स का उपयोग करें find। क्यों कुछ फिर से, कि पहले से ही प्रोग्राम किया गया है? शायद आप की जरूरत नहीं है, लेकिन अभी भी बाहर की जाँच के लायक:

var execFile = require('child_process').execFile;
execFile('find', [ 'somepath/' ], function(err, stdout, stderr) {
  var file_list = stdout.split('\n');
  /* now you've got a list with full path file names */
});

फाइंड में एक अच्छा बिल्ड-इन कैशिंग तंत्र है जो बाद की खोजों को बहुत तेज़ बनाता है, जब तक कि केवल कुछ फ़ोल्डर बदल गए हों।


9
क्या यह केवल यूनिक्स है?
मोहसिन

उदाहरण B के बारे में एक प्रश्न था: निष्पादन के लिए () और (और निष्पादन ()) stderr और stdout बफ़र्स हैं .. इसलिए आपको बफ़र्स स्ट्रिंग्स नहीं है क्योंकि stdout.toString.split ("\ n") करने की आवश्यकता नहीं होगी?
चेरुविम

8
अच्छा है, लेकिन पार मंच नहीं।
f0ster

वैसे: नहीं, ए केवल यूनिक्स नहीं है! केवल बी केवल यूनिक्स है। हालाँकि, विंडोज 10 अब एक लिनक्स सबसिस्टम के साथ आता है। यहां तक ​​कि बी भी आजकल विंडोज पर काम करेगा।
जोहान फिलिप स्ट्रैटहॉज़ेन

विंडोज पर काम करने के लिए अंत उपयोगकर्ताओं को सक्षम नहीं होना चाहिए WSL WSL ??
ओल्डबॉय

38

एक और अच्छा npm पैकेज ग्लोब है

npm install glob

यह बहुत शक्तिशाली है और इसे आपके सभी पुनर्पाठ की जरूरतों को पूरा करना चाहिए।

संपादित करें:

मैं वास्तव में ग्लोब से पूरी तरह से खुश नहीं था, इसलिए मैंने रीडडीआरपी बनाया ।

मुझे बहुत विश्वास है कि इसका एपीआई फाइलों और निर्देशिकाओं को पुनर्संरचना और विशिष्ट फिल्टर लगाने में बहुत आसान बनाता है।

यह क्या करता है और इसके माध्यम से स्थापित करने का एक बेहतर विचार प्राप्त करने के लिए इसके प्रलेखन के माध्यम से पढ़ें :

npm install readdirp


मेरी राय में सबसे अच्छा मॉड्यूल । और कई अन्य परियोजनाओं, जैसे ग्रंट, मोचा, आदि और अन्य 80'000 + अन्य परियोजनाओं के समान है। बस केह रहा हू।
यानिक रोचोन


14

यदि आप एक npm पैकेज का उपयोग करना चाहते हैं, तो रिंच बहुत अच्छा है।

var wrench = require("wrench");

var files = wrench.readdirSyncRecursive("directory");

wrench.readdirRecursive("directory", function (error, files) {
    // live your dreams
});

EDIT (2018):
हाल के समय में कोई भी पढ़ रहा है: लेखक ने 2015 में इस पैकेज को चित्रित किया:

wrench.js को हटा दिया गया है, और काफी समय में अपडेट नहीं किया गया है। मैं किसी भी अतिरिक्त फाइल सिस्टम ऑपरेशन करने के लिए fs-extra का उपयोग करने की जोरदार सलाह देता हूं


@ डॉमिक, आप denodifyयह कैसे करते हैं ? कॉलबैक कई बार (पुनरावर्ती) निकाल दिया जाता है। इसलिए Q.denodify(wrench.readdirRecursive)केवल पहले परिणाम का उपयोग करके ।
ओनुर येल्ड्रिम जुएल

1
@ OnurYıldırım हाँ, यह वादे के लिए एक अच्छा फिट नहीं है जैसा कि है। आपको कुछ लिखने की आवश्यकता होगी जो कई वादे लौटाता है, या कुछ ऐसा होता है जो तब तक इंतजार करता है जब तक कि वादे को पूरा करने से पहले सभी उप-विधायकों की गणना नहीं की जाती है। बाद के लिए, github.com/kriskowal/q-io#listdirectorytreepath
Domenic

9

मैं ऊपर से चज्ज से जवाब पसंद करता था और उस शुरुआत के बिना समानांतर लूप के मेरे संस्करण को बनाने में सक्षम नहीं होता।

var fs = require("fs");

var tree = function(dir, done) {
  var results = {
        "path": dir
        ,"children": []
      };
  fs.readdir(dir, function(err, list) {
    if (err) { return done(err); }
    var pending = list.length;
    if (!pending) { return done(null, results); }
    list.forEach(function(file) {
      fs.stat(dir + '/' + file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          tree(dir + '/' + file, function(err, res) {
            results.children.push(res);
            if (!--pending){ done(null, results); }
          });
        } else {
          results.children.push({"path": dir + "/" + file});
          if (!--pending) { done(null, results); }
        }
      });
    });
  });
};

module.exports = tree;

मैंने एक Gist भी बनाया । टिप्पणियाँ स्वागत है। मैं अभी भी NodeJS दायरे में शुरू कर रहा हूं ताकि एक तरीका है जिससे मुझे और सीखने की उम्मीद है।


9

पुनरावृत्ति के साथ

var fs = require('fs')
var path = process.cwd()
var files = []

var getFiles = function(path, files){
    fs.readdirSync(path).forEach(function(file){
        var subpath = path + '/' + file;
        if(fs.lstatSync(subpath).isDirectory()){
            getFiles(subpath, files);
        } else {
            files.push(path + '/' + file);
        }
    });     
}

कॉलिंग

getFiles(path, files)
console.log(files) // will log all files in directory

3
मेरा सुझाव है /कि pathमॉड्यूल के साथ पथ स्ट्रिंग्स में शामिल न हों path.join(searchPath, file):। इस तरह, आपको ओएस से स्वतंत्र सही रास्ते मिलेंगे।
मोरिट्ज़ फ्रेडरिक

8

अपनी पसंद के उत्पादन के लिए नोड-डीआईआर का उपयोग करें

var dir = require('node-dir');

dir.files(__dirname, function(err, files) {
  if (err) throw err;
  console.log(files);
  //we have an array of files now, so now we can iterate that array
  files.forEach(function(path) {
    action(null, path);
  })
});

नोड-डीआईआर ठीक काम कर रहा था, लेकिन जब मैंने इसे वेबपैक के साथ इस्तेमाल किया तो मेरे पास कुछ अजीब मुद्दे हैं। रीडफाइल्स फ़ंक्शन में "err (इरेट) causing {" के रूप में डाला जाता है, जिसके कारण "अन सेंचुरी सिंटेक्सऑर्डर: अनपेक्षित टोकन {" त्रुटि होती है। मैं इस मुद्दे से स्तब्ध हूं और मेरी तत्काल प्रतिक्रिया नोड-डीआर को कुछ इसी तरह से बदलना है
पार्थ

1
@ इस टिप्पणी का जवाब आपको नहीं देना है। SO पर एक नया पूर्ण प्रश्न लिखें या GitHub रिपॉजिटरी में एक समस्या बनाएं। जब आप अपने प्रश्न पर अच्छी तरह से विस्तार करते हैं, तो आप इसे पोस्ट किए बिना भी अपनी समस्या को हल करने में सक्षम हो सकते हैं
क्रिस्टियान वेस्टरबेक

1
@ पार्थ की टिप्पणी अभी भी उन लोगों के लिए एक उपयोगी चेतावनी हो सकती है जो आपके सुझाव को उनकी समस्या के समाधान के रूप में मान रहे हैं। वे शायद इस टिप्पणी अनुभाग में जवाब की तलाश में नहीं थे :)

4

मैंने हाल ही में इसे कोडित किया है, और सोचा कि इसे यहाँ साझा करने का अर्थ होगा। कोड async लाइब्रेरी का उपयोग करता है ।

var fs = require('fs');
var async = require('async');

var scan = function(dir, suffix, callback) {
  fs.readdir(dir, function(err, files) {
    var returnFiles = [];
    async.each(files, function(file, next) {
      var filePath = dir + '/' + file;
      fs.stat(filePath, function(err, stat) {
        if (err) {
          return next(err);
        }
        if (stat.isDirectory()) {
          scan(filePath, suffix, function(err, results) {
            if (err) {
              return next(err);
            }
            returnFiles = returnFiles.concat(results);
            next();
          })
        }
        else if (stat.isFile()) {
          if (file.indexOf(suffix, file.length - suffix.length) !== -1) {
            returnFiles.push(filePath);
          }
          next();
        }
      });
    }, function(err) {
      callback(err, returnFiles);
    });
  });
};

आप इसे इस तरह से उपयोग कर सकते हैं:

scan('/some/dir', '.ext', function(err, files) {
  // Do something with files that ends in '.ext'.
  console.log(files);
});

2
यह। यह उपयोग करने के लिए बहुत सुव्यवस्थित और सरल है। मैंने इसे एक मॉड्यूल में पंप किया, इसकी आवश्यकता थी और यह एक mcdream सैंडविच की तरह काम करता है।
Jay

4

फाइलहाउंड नामक एक पुस्तकालय एक अन्य विकल्प है। यह किसी दिए गए निर्देशिका (डिफ़ॉल्ट रूप से कार्यशील निर्देशिका) की खोज करेगा। यह विभिन्न फ़िल्टर, कॉलबैक, वादे और सिंक खोजों का समर्थन करता है।

उदाहरण के लिए, सभी फ़ाइलों (कॉलबैक का उपयोग करके) के लिए वर्तमान कार्यशील निर्देशिका खोजें:

const Filehound = require('filehound');

Filehound.create()
.find((err, files) => {
    if (err) {
        return console.error(`error: ${err}`);
    }
    console.log(files); // array of files
});

या वादे और एक विशिष्ट निर्देशिका निर्दिष्ट करना:

const Filehound = require('filehound');

Filehound.create()
.paths("/tmp")
.find()
.each(console.log);

आगे के मामलों और उपयोग के उदाहरणों के लिए डॉक्स से परामर्श करें: https://github.com/nspragg/filehound

डिस्क्लेमर: मैं लेखक हूं।


4

Async / प्रतीक्षा का उपयोग करना, यह काम करना चाहिए:

const FS = require('fs');
const readDir = promisify(FS.readdir);
const fileStat = promisify(FS.stat);

async function getFiles(dir) {
    let files = await readDir(dir);

    let result = files.map(file => {
        let path = Path.join(dir,file);
        return fileStat(path).then(stat => stat.isDirectory() ? getFiles(path) : path);
    });

    return flatten(await Promise.all(result));
}

function flatten(arr) {
    return Array.prototype.concat(...arr);
}

आप उपयोग कर सकते हैं bluebird.Promisify या इस:

/**
 * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
 *
 * @param {Function} nodeFunction
 * @returns {Function}
 */
module.exports = function promisify(nodeFunction) {
    return function(...args) {
        return new Promise((resolve, reject) => {
            nodeFunction.call(this, ...args, (err, data) => {
                if(err) {
                    reject(err);
                } else {
                    resolve(data);
                }
            })
        });
    };
};

नोड 8+ में अंतर्निर्मित निर्मिती है

एक जनरेटर दृष्टिकोण के लिए मेरा दूसरा जवाब देखें जो परिणाम को और भी तेजी से दे सकता है।


4

async

const fs = require('fs')
const path = require('path')

const readdir = (p, done, a = [], i = 0) => fs.readdir(p, (e, d = []) =>
  d.map(f => readdir(a[a.push(path.join(p, f)) - 1], () =>
    ++i == d.length && done(a), a)).length || done(a))

readdir(__dirname, console.log)

सिंक

const fs = require('fs')
const path = require('path')

const readdirSync = (p, a = []) => {
  if (fs.statSync(p).isDirectory())
    fs.readdirSync(p).map(f => readdirSync(a[a.push(path.join(p, f)) - 1], a))
  return a
}

console.log(readdirSync(__dirname))

Async पठनीय

function readdir (currentPath, done, allFiles = [], i = 0) {
  fs.readdir(currentPath, function (e, directoryFiles = []) {
    if (!directoryFiles.length)
      return done(allFiles)
    directoryFiles.map(function (file) {
      var joinedPath = path.join(currentPath, file)
      allFiles.push(joinedPath)
      readdir(joinedPath, function () {
        i = i + 1
        if (i == directoryFiles.length)
          done(allFiles)}
      , allFiles)
    })
  })
}

readdir(__dirname, console.log)

नोट: दोनों संस्करण सिमिलिंक का अनुसरण करेंगे (मूल के समान fs.readdir)


3

की जाँच करें अंतिम-FS पुस्तकालय। यह एक readdirRecursiveफ़ंक्शन प्रदान करता है :

ffs.readdirRecursive(dirPath, true, 'my/initial/path')
    .then(function (files) {
        // in the `files` variable you've got all the files
    })
    .otherwise(function (err) {
        // something went wrong
    });

2

स्टैंडअलोन वादा कार्यान्वयन

मैं उपयोग कर रहा हूँ when.js इस उदाहरण में वादा पुस्तकालय।

var fs = require('fs')
, path = require('path')
, when = require('when')
, nodefn = require('when/node/function');

function walk (directory, includeDir) {
    var results = [];
    return when.map(nodefn.call(fs.readdir, directory), function(file) {
        file = path.join(directory, file);
        return nodefn.call(fs.stat, file).then(function(stat) {
            if (stat.isFile()) { return results.push(file); }
            if (includeDir) { results.push(file + path.sep); }
            return walk(file, includeDir).then(function(filesInDir) {
                results = results.concat(filesInDir);
            });
        });
    }).then(function() {
        return results;
    });
};

walk(__dirname).then(function(files) {
    console.log(files);
}).otherwise(function(error) {
    console.error(error.stack || error);
});

मैंने एक वैकल्पिक पैरामीटर शामिल किया है, includeDirजो यदि सेट किया जाता है तो फ़ाइल लिस्टिंग में निर्देशिका शामिल होगी true



1

यहाँ एक और कार्यान्वयन अभी तक है। उपरोक्त समाधानों में से किसी की भी कोई सीमा नहीं है, और इसलिए यदि आपकी निर्देशिका संरचना बड़ी है, तो वे सभी थ्रैश होने वाले हैं और अंततः संसाधनों से बाहर निकलते हैं।

var async = require('async');
var fs = require('fs');
var resolve = require('path').resolve;

var scan = function(path, concurrency, callback) {
    var list = [];

    var walker = async.queue(function(path, callback) {
        fs.stat(path, function(err, stats) {
            if (err) {
                return callback(err);
            } else {
                if (stats.isDirectory()) {
                    fs.readdir(path, function(err, files) {
                        if (err) {
                            callback(err);
                        } else {
                            for (var i = 0; i < files.length; i++) {
                                walker.push(resolve(path, files[i]));
                            }
                            callback();
                        }
                    });
                } else {
                    list.push(path);
                    callback();
                }
            }
        });
    }, concurrency);

    walker.push(path);

    walker.drain = function() {
        callback(list);
    }
};

50 की एक संगामिति का उपयोग करना बहुत अच्छी तरह से काम करता है, और छोटे निर्देशिका संरचनाओं के लिए लगभग उतना ही सरल कार्यान्वयन है।



1

मैंने ब्लूबर्ड के साथ काम करने के लिए ट्रेवर सीनियर के प्रॉमिस आधारित उत्तर को संशोधित किया

var fs = require('fs'),
    path = require('path'),
    Promise = require('bluebird');

var readdirAsync = Promise.promisify(fs.readdir);
var statAsync = Promise.promisify(fs.stat);
function walkFiles (directory) {
    var results = [];
    return readdirAsync(directory).map(function(file) {
        file = path.join(directory, file);
        return statAsync(file).then(function(stat) {
            if (stat.isFile()) {
                return results.push(file);
            }
            return walkFiles(file).then(function(filesInDir) {
                results = results.concat(filesInDir);
            });
        });
    }).then(function() {
        return results;
    });
}

//use
walkDir(__dirname).then(function(files) {
    console.log(files);
}).catch(function(e) {
    console.error(e); {
});

1

मज़े के लिए, यहाँ एक प्रवाह आधारित संस्करण है जो हाईलैंड के साथ काम करता है। यह विक्टर वू द्वारा सह-लेखक था।

###
  directory >---m------> dirFilesStream >---------o----> out
                |                                 |
                |                                 |
                +--------< returnPipe <-----------+

  legend: (m)erge  (o)bserve

 + directory         has the initial file
 + dirListStream     does a directory listing
 + out               prints out the full path of the file
 + returnPipe        runs stat and filters on directories

###

_ = require('highland')
fs = require('fs')
fsPath = require('path')

directory = _(['someDirectory'])
mergePoint = _()
dirFilesStream = mergePoint.merge().flatMap((parentPath) ->
  _.wrapCallback(fs.readdir)(parentPath).sequence().map (path) ->
    fsPath.join parentPath, path
)
out = dirFilesStream
# Create the return pipe
returnPipe = dirFilesStream.observe().flatFilter((path) ->
  _.wrapCallback(fs.stat)(path).map (v) ->
    v.isDirectory()
)
# Connect up the merge point now that we have all of our streams.
mergePoint.write directory
mergePoint.write returnPipe
mergePoint.end()
# Release backpressure.  This will print files as they are discovered
out.each H.log
# Another way would be to queue them all up and then print them all out at once.
# out.toArray((files)-> console.log(files))

1

कार्यात्मक शैली में इसे हल करने के लिए वादे ( क्यू ) का उपयोग करना :

var fs = require('fs'),
    fsPath = require('path'),
    Q = require('q');

var walk = function (dir) {
  return Q.ninvoke(fs, 'readdir', dir).then(function (files) {

    return Q.all(files.map(function (file) {

      file = fsPath.join(dir, file);
      return Q.ninvoke(fs, 'lstat', file).then(function (stat) {

        if (stat.isDirectory()) {
          return walk(file);
        } else {
          return [file];
        }
      });
    }));
  }).then(function (files) {
    return files.reduce(function (pre, cur) {
      return pre.concat(cur);
    });
  });
};

यह एक सरणी का वादा देता है, इसलिए आप इसका उपयोग इस प्रकार कर सकते हैं:

walk('/home/mypath').then(function (files) { console.log(files); });

1

मुझे सूची में प्रोमिस-आधारित सैंडर लाइब्रेरी जोड़ना होगा ।

 var sander = require('sander');
 sander.lsr(directory).then( filenames => { console.log(filenames) } );

1

Bluebird वादा का उपयोग कर।

let promise = require('bluebird'),
    PC = promise.coroutine,
    fs = promise.promisifyAll(require('fs'));
let getFiles = PC(function*(dir){
    let files = [];
    let contents = yield fs.readdirAsync(dir);
    for (let i = 0, l = contents.length; i < l; i ++) {
        //to remove dot(hidden) files on MAC
        if (/^\..*/.test(contents[i])) contents.splice(i, 1);
    }
    for (let i = 0, l = contents.length; i < l; i ++) {
        let content = path.resolve(dir, contents[i]);
        let contentStat = yield fs.statAsync(content);
        if (contentStat && contentStat.isDirectory()) {
            let subFiles = yield getFiles(content);
            files = files.concat(subFiles);
        } else {
            files.push(content);
        }
    }
    return files;
});
//how to use
//easy error handling in one place
getFiles(your_dir).then(console.log).catch(err => console.log(err));

0

क्योंकि सभी को अपना लिखना चाहिए, मैंने एक बनाया।

चलना (डीआईआर, सीबी, एंडकब) सीबी (फाइल) एंडकब (इरेट | नल)

गंदा

module.exports = walk;

function walk(dir, cb, endCb) {
  var fs = require('fs');
  var path = require('path');

  fs.readdir(dir, function(err, files) {
    if (err) {
      return endCb(err);
    }

    var pending = files.length;
    if (pending === 0) {
      endCb(null);
    }
    files.forEach(function(file) {
      fs.stat(path.join(dir, file), function(err, stats) {
        if (err) {
          return endCb(err)
        }

        if (stats.isDirectory()) {
          walk(path.join(dir, file), cb, function() {
            pending--;
            if (pending === 0) {
              endCb(null);
            }
          });
        } else {
          cb(path.join(dir, file));
          pending--;
          if (pending === 0) {
            endCb(null);
          }
        }
      })
    });

  });
}

0

Check out loaddir https://npmjs.org/package/loaddir

npm install loaddir

  loaddir = require('loaddir')

  allJavascripts = []
  loaddir({
    path: __dirname + '/public/javascripts',
    callback: function(){  allJavascripts.push(this.relativePath + this.baseName); }
  })

यदि आपको एक्सटेंशन की आवश्यकता है तो आप fileNameइसके बजाय उपयोग कर सकते हैं baseName

एक अतिरिक्त बोनस यह है कि यह फाइलों को भी देखेगा और कॉलबैक को फिर से कॉल करेगा। इसे अत्यंत लचीला बनाने के लिए कई टन विन्यास विकल्प हैं।

मैं बस guardथोड़ी देर में लोडडिर का उपयोग करके माणिक से मणि निकालता हूं


0

यह मेरा जवाब है। आशा है कि यह किसी की मदद कर सकता है।

मेरा ध्यान यह है कि सर्चिंग रूटीन को कहीं भी रोका जा सकता है, और पाया गया फाइल के लिए, मूल पथ के सापेक्ष गहराई को बताता है।

var _fs = require('fs');
var _path = require('path');
var _defer = process.nextTick;

// next() will pop the first element from an array and return it, together with
// the recursive depth and the container array of the element. i.e. If the first
// element is an array, it'll be dug into recursively. But if the first element is
// an empty array, it'll be simply popped and ignored.
// e.g. If the original array is [1,[2],3], next() will return [1,0,[[2],3]], and
// the array becomes [[2],3]. If the array is [[[],[1,2],3],4], next() will return
// [1,2,[2]], and the array becomes [[[2],3],4].
// There is an infinity loop `while(true) {...}`, because I optimized the code to
// make it a non-recursive version.
var next = function(c) {
    var a = c;
    var n = 0;
    while (true) {
        if (a.length == 0) return null;
        var x = a[0];
        if (x.constructor == Array) {
            if (x.length > 0) {
                a = x;
                ++n;
            } else {
                a.shift();
                a = c;
                n = 0;
            }
        } else {
            a.shift();
            return [x, n, a];
        }
    }
}

// cb is the callback function, it have four arguments:
//    1) an error object if any exception happens;
//    2) a path name, may be a directory or a file;
//    3) a flag, `true` means directory, and `false` means file;
//    4) a zero-based number indicates the depth relative to the original path.
// cb should return a state value to tell whether the searching routine should
// continue: `true` means it should continue; `false` means it should stop here;
// but for a directory, there is a third state `null`, means it should do not
// dig into the directory and continue searching the next file.
var ls = function(path, cb) {
    // use `_path.resolve()` to correctly handle '.' and '..'.
    var c = [ _path.resolve(path) ];
    var f = function() {
        var p = next(c);
        p && s(p);
    };
    var s = function(p) {
        _fs.stat(p[0], function(err, ss) {
            if (err) {
                // use `_defer()` to turn a recursive call into a non-recursive call.
                cb(err, p[0], null, p[1]) && _defer(f);
            } else if (ss.isDirectory()) {
                var y = cb(null, p[0], true, p[1]);
                if (y) r(p);
                else if (y == null) _defer(f);
            } else {
                cb(null, p[0], false, p[1]) && _defer(f);
            }
        });
    };
    var r = function(p) {
        _fs.readdir(p[0], function(err, files) {
            if (err) {
                cb(err, p[0], true, p[1]) && _defer(f);
            } else {
                // not use `Array.prototype.map()` because we can make each change on site.
                for (var i = 0; i < files.length; i++) {
                    files[i] = _path.join(p[0], files[i]);
                }
                p[2].unshift(files);
                _defer(f);
            }
        });
    }
    _defer(f);
};

var printfile = function(err, file, isdir, n) {
    if (err) {
        console.log('-->   ' + ('[' + n + '] ') + file + ': ' + err);
        return true;
    } else {
        console.log('... ' + ('[' + n + '] ') + (isdir ? 'D' : 'F') + ' ' + file);
        return true;
    }
};

var path = process.argv[2];
ls(path, printfile);

0

यहाँ उपनिर्देशिका सहित सभी फ़ाइलों को प्राप्त करने की एक पुनरावर्ती विधि है।

const FileSystem = require("fs");
const Path = require("path");

//...

function getFiles(directory) {
    directory = Path.normalize(directory);
    let files = FileSystem.readdirSync(directory).map((file) => directory + Path.sep + file);

    files.forEach((file, index) => {
        if (FileSystem.statSync(file).isDirectory()) {
            Array.prototype.splice.apply(files, [index, 1].concat(getFiles(file)));
        }
    });

    return files;
}

0

एक और सरल और सहायक

function walkDir(root) {
    const stat = fs.statSync(root);

    if (stat.isDirectory()) {
        const dirs = fs.readdirSync(root).filter(item => !item.startsWith('.'));
        let results = dirs.map(sub => walkDir(`${root}/${sub}`));
        return [].concat(...results);
    } else {
        return root;
    }
}

आप मान रहे हैं कि रूट डायरेक्टरी की हर फाइल यहां एक फोल्डर है।
xechelonx

0

यह है कि मैं एक निर्देशिका को पुन: खोज करने के लिए नोडजेस fs.readdir फ़ंक्शन का उपयोग करता हूं।

const fs = require('fs');
const mime = require('mime-types');
const readdirRecursivePromise = path => {
    return new Promise((resolve, reject) => {
        fs.readdir(path, (err, directoriesPaths) => {
            if (err) {
                reject(err);
            } else {
                if (directoriesPaths.indexOf('.DS_Store') != -1) {
                    directoriesPaths.splice(directoriesPaths.indexOf('.DS_Store'), 1);
                }
                directoriesPaths.forEach((e, i) => {
                    directoriesPaths[i] = statPromise(`${path}/${e}`);
                });
                Promise.all(directoriesPaths).then(out => {
                    resolve(out);
                }).catch(err => {
                    reject(err);
                });
            }
        });
    });
};
const statPromise = path => {
    return new Promise((resolve, reject) => {
        fs.stat(path, (err, stats) => {
            if (err) {
                reject(err);
            } else {
                if (stats.isDirectory()) {
                    readdirRecursivePromise(path).then(out => {
                        resolve(out);
                    }).catch(err => {
                        reject(err);
                    });
                } else if (stats.isFile()) {
                    resolve({
                        'path': path,
                        'type': mime.lookup(path)
                    });
                } else {
                    reject(`Error parsing path: ${path}`);
                }
            }
        });
    });
};
const flatten = (arr, result = []) => {
    for (let i = 0, length = arr.length; i < length; i++) {
        const value = arr[i];
        if (Array.isArray(value)) {
            flatten(value, result);
        } else {
            result.push(value);
        }
    }
    return result;
};

मान लीजिए कि आपके नोड प्रोजेक्ट्स रूट में '/ डेटाबेस' नामक एक पथ है। एक बार इस वादे को हल करने के बाद, इसे '/ डेटाबेस' के तहत हर फ़ाइल की एक सरणी को थूक देना चाहिए।

readdirRecursivePromise('database').then(out => {
    console.log(flatten(out));
}).catch(err => {
    console.log(err);
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.