2011-08-12 3 views
17

मैं node.js. में इस कोड के साथ एक समस्या मिल गया है मैं रिकर्सिवली एक निर्देशिका वृक्ष के माध्यम से चलना और पेड़ में हर फाइल करने के लिए कॉलबैक action लागू करना चाहते हैं।Node.js के साथ एक निर्देशिका चलना

var fs = require("fs"); 

// General function 
var dive = function (dir, action) { 
    // Assert that it's a function 
    if (typeof action !== "function") 
    action = function (error, file) { }; 

    // Read the directory 
    fs.readdir(dir, function (err, list) { 
    // Return the error if something went wrong 
    if (err) 
     return action(err); 

    // For every file in the list 
    list.forEach(function (file) { 
     // Full path of that file 
     path = dir + "/" + file; 
     // Get the file's stats 
     fs.stat(path, function (err, stat) { 
     console.log(stat); 
     // If the file is a directory 
     if (stat && stat.isDirectory()) 
      // Dive into the directory 
      dive(path, action); 
     else 
      // Call the action 
      action(null, path); 
     }); 
    }); 
    }); 
}; 

समस्या यह है कि प्रत्येक पाश के लिए में स्टेट चर path के माध्यम से हर फ़ाइल के लिए कहा जाता है: इस पल में मेरी कोड है। जब कॉलबैक कहा जाता है, path पहले से ही एक और मूल्य और गलत निर्देशिका में तो यह dive रों है या गलत फ़ाइलों के लिए action कहता है।

शायद इस समस्या को आसानी से fs.statSync का उपयोग कर हल किया जा सकता है, लेकिन यह वह समाधान नहीं है जिसे मैं पसंद करूंगा, क्योंकि यह प्रक्रिया को अवरुद्ध कर रहा है।

उत्तर

14

var path = dir + "/" + file;

आप path एक स्थानीय चर बनाने के लिए भूल गया था। अब यह लूप में आपकी पीठ के पीछे नहीं बदला जाएगा।

+2

अंतिम [एनपीएम पैकेज] (http://search.npmjs.org/#/dive) – pvorb

+5

यह आपकी फ़ाइल के शीर्ष पर 'सख्त उपयोग "डालने से पकड़ा गया होगा। – Domenic

+2

क्रॉस-प्लेटफ़ॉर्म संगतता के लिए, कच्चे '"/"' को जोड़ने के बजाय नोड के [path.join] (http://nodejs.org/api/path.html#path_path_join_path1_path2) फ़ंक्शन का उपयोग करें। –

-1
function loop() { 
    var item = list.shift(); 
    if (item) { 
     // content of the loop 
     functionWithCallback(loop); 
    } else { 
     // after the loop has ended 
     whatever(); 
    } 
} 
+0

यह स्पष्ट नहीं होता है कि आप मुझे 'functionWithCallback (लूप) में क्या करना चाहते हैं; '। क्या आप अपना उदाहरण मेरे उदाहरण पर लागू कर सकते हैं? – pvorb

+0

अच्छी तरह से सूची के प्रत्येक तत्व के लिए आप कुछ करना चाहते हैं और यह फ़ंक्शन करता है और फिर कॉलबैक को कॉल करता है। मैं इसे आपके कोड के करीब बनाने के लिए टॉमोरो संपादित करूंगा। – xavierm02

7

अगर मैं वास्तव में एक जवाब के रूप में पोस्ट करना चाहिए कि, लेकिन आपकी सुविधा और अन्य उपयोगकर्ताओं के लिए नहीं है, यहाँ जो उपयोगी साबित हो सकता है ओ पी के एक पुनः संस्करण है। यह प्रदान करता है:

  • बेहतर त्रुटि प्रबंधन का समर्थन
  • एक वैश्विक पूरा होने कॉलबैक जो जब अन्वेषण पूरा हो गया है

कोड कहा जाता है:

/** 
* dir: path to the directory to explore 
* action(file, stat): called on each file or until an error occurs. file: path to the file. stat: stat of the file (retrived by fs.stat) 
* done(err): called one time when the process is complete. err is undifined is everything was ok. the error that stopped the process otherwise 
*/ 
var walk = function(dir, action, done) { 

    // this flag will indicate if an error occured (in this case we don't want to go on walking the tree) 
    var dead = false; 

    // this flag will store the number of pending async operations 
    var pending = 0; 

    var fail = function(err) { 
     if(!dead) { 
      dead = true; 
      done(err); 
     } 
    }; 

    var checkSuccess = function() { 
     if(!dead && pending == 0) { 
      done(); 
     } 
    }; 

    var performAction = function(file, stat) { 
     if(!dead) { 
      try { 
       action(file, stat); 
      } 
      catch(error) { 
       fail(error); 
      } 
     } 
    }; 

    // this function will recursively explore one directory in the context defined by the variables above 
    var dive = function(dir) { 
     pending++; // async operation starting after this line 
     fs.readdir(dir, function(err, list) { 
      if(!dead) { // if we are already dead, we don't do anything 
       if (err) { 
        fail(err); // if an error occured, let's fail 
       } 
       else { // iterate over the files 
        list.forEach(function(file) { 
         if(!dead) { // if we are already dead, we don't do anything 
          var path = dir + "/" + file; 
          pending++; // async operation starting after this line 
          fs.stat(path, function(err, stat) { 
           if(!dead) { // if we are already dead, we don't do anything 
            if (err) { 
             fail(err); // if an error occured, let's fail 
            } 
            else { 
             if (stat && stat.isDirectory()) { 
              dive(path); // it's a directory, let's explore recursively 
             } 
             else { 
              performAction(path, stat); // it's not a directory, just perform the action 
             } 
             pending--; checkSuccess(); // async operation complete 
            } 
           } 
          }); 
         } 
        }); 
        pending--; checkSuccess(); // async operation complete 
       } 
      } 
     }); 
    }; 

    // start exploration 
    dive(dir); 
}; 
+0

यह बहुत अच्छा है! एक छोटा सा अनुकूलन: आपको पहले लंबित होने के बाद चेकस्यूफ की आवश्यकता नहीं है -। आप तब तक लंबित नहीं हो सकते हैं जब तक कि आप उस निर्देशिका को पूरा नहीं कर लेते हैं, जिसमें आप वर्तमान में हैं। –

2

पहिया बदलने मत करो - इसके बजाय ओपन सोर्स का उपयोग करें और योगदान दें। निम्न में से एक का प्रयास करें: इस के लिए

+4

मुझे वह मॉड्यूल पसंद नहीं है। [यह एक] (https://npmjs.org/package/dive) (जो इस प्रश्न का परिणाम था) में एक बहुत आसान एपीआई है। – pvorb

8

उपयोग node-dir। क्योंकि आपको निर्देशिकाओं और फ़ाइलों के लिए एक अलग कार्रवाई की आवश्यकता है, इसलिए मैं आपको नोड-डीआईआर का उपयोग करके 2 सरल इटरेटर प्रदान करूंगा।

असीमित रूप से निर्देशिका और इसकी उपनिर्देशिका की फ़ाइलों को पुन: सक्रिय करें और कॉलबैक में फ़ाइल पथों की एक सरणी पास करें।

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'll iterate that array 
    files.forEach(function(filepath) { 
    actionOnFile(null, filepath); 
    }) 
}); 

एसिंक्रोनस रूप से एक निर्देशिका और उसकी उप की उपनिर्देशिका पुनरावृति और एक कॉलबैक करने के लिए निर्देशिका पथ की एक सरणी गुजरती हैं।

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

dir.subdirs(__dirname, function(err, subdirs) { 
    if (err) throw err; 
    console.log(subdirs); 
    //we have an array of subdirs now, so now we'll iterate that array 
    subdirs.forEach(function(filepath) { 
    actionOnDir(null, filepath); 
    }) 
}); 
7

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

उदाहरण के लिए:

const Filehound = require('filehound'); 

function action(file) { 
    console.log(`process ${file}`) 
} 

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

    files.forEach(action); 
}); 

पुस्तकालय अच्छी तरह से प्रलेखित और सामान्य उपयोग के मामलों के कई उदाहरण प्रदान करता है। https://github.com/nspragg/filehound

अस्वीकरण: मैं लेखक हूं।