एक निर्देशिका में सभी फ़ाइलों को पढ़ना, उन्हें वस्तुओं में संग्रहीत करना और ऑब्जेक्ट भेजना


91

मुझे नहीं पता कि यह संभव है, लेकिन यहां जाता है। और कॉलबैक के साथ काम करना और भी मुश्किल हो जाता है।

मेरे पास HTML फ़ाइलों के साथ एक निर्देशिका है जिसे मैं नोड.जेएस और सॉकेट के साथ ऑब्जेक्ट चंक्स में क्लाइंट को वापस भेजना चाहता हूं।

मेरी सभी फाइलें / tmpl में हैं

तो सॉकेट को / tmpl में सभी फाइलों को पढ़ने की जरूरत है।

प्रत्येक फ़ाइल के लिए डेटा को कुंजी के रूप में फ़ाइल नाम के साथ ऑब्जेक्ट में संग्रहीत करना पड़ता है, और मूल्य के रूप में सामग्री।

  var data;
  // this is wrong because it has to loop trough all files.
  fs.readFile(__dirname + '/tmpl/filename.html', 'utf8', function(err, html){
      if(err) throw err;
      //filename must be without .html at the end
      data['filename'] = html;
  });
  socket.emit('init', {data: data});

अंतिम कॉलबैक भी गलत है। इसे तब बुलाया जाना है जब निर्देशिका की सभी फाइलें हो जाए।

लेकिन मुझे नहीं पता कि कोड कैसे बनाया जाए, किसी को पता है कि क्या यह कब्ज़ है?


4
यदि तुल्यकालिक पहुंच ठीक है, तो आप (अवरुद्ध) readfileSyncऔर readdirSyncविधियों का उपयोग करके ईवेंट हैंडलर को छोड़ सकते हैं । nodejs.org/docs/v0.4.8/api/fs.html#fs.readdirSync
rjz

ठीक है, मुझे रीडडीर के बारे में नहीं पता था, जो सहायक हो सकता है। और ब्लॉकिंग के डाउनसाइड क्या हैं। मुझे लगा कि नोड.जेएस का पूरा बिंदु यह है कि यह गैर-अवरुद्ध था? हम सभी अचानक ब्लॉक क्यों कर सकते हैं।
बजे सैफ बेचन

Async कॉलबैक के लिए इसे पढ़ें: stackoverflow.com/questions/18983138/… कई गलत उत्तर हैं, लेकिन कुछ सही हैं। उनमें से एक काउंटर का उपयोग करता है।
वानुआन

जवाबों:


169

तो, तीन भाग हैं। पढ़ना, भंडारण और भेजना।

यहाँ पढ़ने हिस्सा है:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
  fs.readdir(dirname, function(err, filenames) {
    if (err) {
      onError(err);
      return;
    }
    filenames.forEach(function(filename) {
      fs.readFile(dirname + filename, 'utf-8', function(err, content) {
        if (err) {
          onError(err);
          return;
        }
        onFileContent(filename, content);
      });
    });
  });
}

यहाँ भंडारण भाग है:

var data = {};
readFiles('dirname/', function(filename, content) {
  data[filename] = content;
}, function(err) {
  throw err;
});

भेजने वाला हिस्सा आपके ऊपर है। आप उन्हें एक-एक करके या पूरा पढ़ने के बाद भेज सकते हैं।

यदि आप पूर्णता पढ़ने के बाद फाइलें भेजना चाहते हैं, तो आपको या तो fsफ़ंक्शन के सिंक संस्करणों का उपयोग करना चाहिए या वादों का उपयोग करना चाहिए । Async कॉलबैक एक अच्छी शैली नहीं है।

इसके अतिरिक्त आपने एक्सटेंशन बढ़ाने के बारे में पूछा। आपको एक-एक करके प्रश्नों के साथ आगे बढ़ना चाहिए। कोई भी आपके लिए पूर्ण समाधान नहीं लिखेगा।


धन्यवाद, मुझे लगता है कि मैं इसका उपयोग करूंगा। एक बात, क्या आप समझा सकते हैं कि क्या 0===--cकरता है।
सैफ बेचन

1
आप इसे दो पंक्तियों के रूप में लिख सकते हैं c--और फिर if (c===0)वही कर सकते हैं। यह शून्य से c1
घटता

लेकिन यह हमेशा 0 होगा, या नहीं? आप फ़ॉर्च में 1 जोड़ते हैं, और उसी फ़ॉर्च में आप 1 निकालते हैं, इसलिए यह हमेशा 0 रहता है, या मैं गलत हूँ? चेक की जरूरत नहीं है if(c===files.length), ऐसा कुछ है।
सैफ बेचन

5
Async प्रकृति के कारण foreach पाश सबसे अधिक संभावना खत्म करने से पहले readFileएचटीएमएल दिया जाता है, तो cऊपर के पास जाना चाहिए x(फ़ाइलों की संख्या) तुरंत और फिर घटती जब एचटीएमएल डिस्क से आता है (जो बहुत बाद में)
stewe

1
ओह, यह कुछ गहरा तर्क है, अच्छा है। नोड के बारे में जानने के लिए बहुत कुछ मिला। सहायता के लिए धन्यवाद!
सैफ बेनकॉन

16

यह Promiseपिछले सभी का एक आधुनिक संस्करण है, जिसमें Promise.allसभी फाइलों को पढ़ने के बाद सभी वादों को हल करने के लिए एक दृष्टिकोण का उपयोग किया गया है:

/**
 * Promise all
 * @author Loreto Parisi (loretoparisi at gmail dot com)
 */
function promiseAllP(items, block) {
    var promises = [];
    items.forEach(function(item,index) {
        promises.push( function(item,i) {
            return new Promise(function(resolve, reject) {
                return block.apply(this,[item,index,resolve,reject]);
            });
        }(item,index))
    });
    return Promise.all(promises);
} //promiseAll

/**
 * read files
 * @param dirname string
 * @return Promise
 * @author Loreto Parisi (loretoparisi at gmail dot com)
 * @see http://stackoverflow.com/questions/10049557/reading-all-files-in-a-directory-store-them-in-objects-and-send-the-object
 */
function readFiles(dirname) {
    return new Promise((resolve, reject) => {
        fs.readdir(dirname, function(err, filenames) {
            if (err) return reject(err);
            promiseAllP(filenames,
            (filename,index,resolve,reject) =>  {
                fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
                    if (err) return reject(err);
                    return resolve({filename: filename, contents: content});
                });
            })
            .then(results => {
                return resolve(results);
            })
            .catch(error => {
                return reject(error);
            });
        });
  });
}

इसे कैसे उपयोग करे:

बस के रूप में कर के रूप में सरल:

readFiles( EMAIL_ROOT + '/' + folder)
.then(files => {
    console.log( "loaded ", files.length );
    files.forEach( (item, index) => {
        console.log( "item",index, "size ", item.contents.length);
    });
})
.catch( error => {
    console.log( error );
});

माना जाता है कि आपके पास उन फ़ोल्डरों की एक और सूची है जो आप इस सूची पर अच्छी तरह से पुनरावृत्त कर सकते हैं, क्योंकि आंतरिक वादा.सभी तब अतुल्यकालिक रूप से प्रत्येक को हल करेगा:

var folders=['spam','ham'];
folders.forEach( folder => {
    readFiles( EMAIL_ROOT + '/' + folder)
    .then(files => {
        console.log( "loaded ", files.length );
        files.forEach( (item, index) => {
            console.log( "item",index, "size ", item.contents.length);
        });
    })
    .catch( error => {
        console.log( error );
    });
});

यह काम किस प्रकार करता है

promiseAllजादू करता है। यह हस्ताक्षर के एक समारोह ब्लॉक लेता है function(item,index,resolve,reject), जहां itemसरणी में वर्तमान आइटम, है indexसरणी में अपनी स्थिति, और resolveऔर कॉलबैक कार्य करता है। प्रत्येक वादे को वर्तमान में और वर्तमान फ़ंक्शन के साथ अनाम फ़ंक्शन कॉल के माध्यम से तर्क के रूप में धकेल दिया जाएगा :rejectPromiseindexitem

promises.push( function(item,i) {
        return new Promise(function(resolve, reject) {
            return block.apply(this,[item,index,resolve,reject]);
        });
    }(item,index))

तब सभी वादों को हल किया जाएगा:

return Promise.all(promises);

1
महान कोड लोरेटो, लेकिन return block(item,index,resolve,reject);इसके बजाय का उपयोग क्यों नहीं करते हैं return block.apply(this,[item,index,resolve,reject]);, मुझे लगता है applyकि यह समझना मुश्किल हो जाता है - क्या कोई लाभ है जो मुझे पता नहीं है?
NULL पॉइंटर

1
@NULLpointer धन्यवाद। लागू होने के लाभों में से एक यह है कि आप आर्गेज को पास करने के लिए सरणियों का उपयोग कर सकते हैं और अधिक आप उस संदर्भ को पास कर सकते हैं जहां चर स्वयं की तरह परिभाषित होते हैं (someObjContext, [arg1, arg2])। इस विशिष्ट मामले में आपको वास्तव में इसकी आवश्यकता नहीं है, लेकिन यदि आप एक पुस्तकालय में हैं तो यह वस्तु संदर्भ कुछ और हो सकता है ...
loretoparisi

10

नीचे दिए गए सभी उदाहरणों के लिए आपको fs और पथ मॉड्यूल आयात करने की आवश्यकता है :

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

फ़ाइलों को असिंक्रोनस रूप से पढ़ें

function readFiles(dir, processFile) {
  // read directory
  fs.readdir(dir, (error, fileNames) => {
    if (error) throw error;

    fileNames.forEach(filename => {
      // get current file name
      const name = path.parse(filename).name;
      // get current file extension
      const ext = path.parse(filename).ext;
      // get current file path
      const filepath = path.resolve(dir, filename);

      // get information about the file
      fs.stat(filepath, function(error, stat) {
        if (error) throw error;

        // check if the current path is a file or a folder
        const isFile = stat.isFile();

        // exclude folders
        if (isFile) {
          // callback, do something with the file
          processFile(filepath, name, ext, stat);
        }
      });
    });
  });
}

उपयोग:

// use an absolute path to the folder where files are located
readFiles('absolute/path/to/directory/', (filepath, name, ext, stat) => {
  console.log('file path:', filepath);
  console.log('file name:', name);
  console.log('file extension:', ext);
  console.log('file information:', stat);
});

फ़ाइलों को समकालिक रूप से पढ़ें, सरणी में संग्रहीत करें, प्राकृतिक छँटाई करें

/**
 * @description Read files synchronously from a folder, with natural sorting
 * @param {String} dir Absolute path to directory
 * @returns {Object[]} List of object, each object represent a file
 * structured like so: `{ filepath, name, ext, stat }`
 */
function readFilesSync(dir) {
  const files = [];

  fs.readdirSync(dir).forEach(filename => {
    const name = path.parse(filename).name;
    const ext = path.parse(filename).ext;
    const filepath = path.resolve(dir, filename);
    const stat = fs.statSync(filepath);
    const isFile = stat.isFile();

    if (isFile) files.push({ filepath, name, ext, stat });
  });

  files.sort((a, b) => {
    // natural sort alphanumeric strings
    // https://stackoverflow.com/a/38641281
    return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' });
  });

  return files;
}

उपयोग:

// return an array list of objects
// each object represent a file
const files = readFilesSync('absolute/path/to/directory/');

वादा का उपयोग करते हुए फ़ाइलें async पढ़ें

इस लेख में प्रॉमिस पर अधिक जानकारी ।

const { promisify } = require('util');

const readdir_promise = promisify(fs.readdir);
const stat_promise = promisify(fs.stat);

function readFilesAsync(dir) {
  return readdir_promise(dir, { encoding: 'utf8' })
    .then(filenames => {
      const files = getFiles(dir, filenames);

      return Promise.all(files);
    })
    .catch(err => console.error(err));
}

function getFiles(dir, filenames) {
  return filenames.map(filename => {
    const name = path.parse(filename).name;
    const ext = path.parse(filename).ext;
    const filepath = path.resolve(dir, filename);

    return stat({ name, ext, filepath });
  });
}

function stat({ name, ext, filepath }) {
  return stat_promise(filepath)
    .then(stat => {
      const isFile = stat.isFile();

      if (isFile) return { name, ext, filepath, stat };
    })
    .catch(err => console.error(err));
}

उपयोग:

readFiles('absolute/path/to/directory/')
  // return an array list of objects
  // each object is a file
  // with those properties: { name, ext, filepath, stat }
  .then(files => console.log(files))
  .catch(err => console.log(err));

नोट:undefined फ़ोल्डरों के लिए वापसी , यदि आप चाहें तो आप उन्हें फ़िल्टर कर सकते हैं:

readFiles('absolute/path/to/directory/')
  .then(files => files.filter(file => file !== undefined))
  .catch(err => console.log(err));

5

क्या आप मेरे जैसे आलसी व्यक्ति हैं और npm मॉड्यूल को प्यार करते हैं : D तो इसे देखें।

npm नोड-डीआईआर स्थापित करें

फ़ाइलों को पढ़ने के लिए उदाहरण:

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

dir.readFiles(__dirname,
    function(err, content, next) {
        if (err) throw err;
        console.log('content:', content);  // get content of files
        next();
    },
    function(err, files){
        if (err) throw err;
        console.log('finished reading files:', files); // get filepath 
   });    

4

यदि आपके पास Node.js 8 या बाद का है, तो आप नए उपयोग का उपयोग कर सकते हैं। (मैं कोड के कुछ हिस्सों को वैकल्पिक के रूप में चिह्नित कर रहा हूं जो एक ऑब्जेक्ट के रूप में पुन: स्वरूपण के साथ करना है, जो कि मूल पोस्ट अनुरोध करता है।)

  const fs = require('fs');
  const { promisify } = require('util');

  let files; // optional
  promisify(fs.readdir)(directory).then((filenames) => {
    files = filenames; // optional
    return Promise.all(filenames.map((filename) => {
      return promisify(fs.readFile)(directory + filename, {encoding: 'utf8'});
    }));
  }).then((strArr) => {
    // optional:
    const data = {};
    strArr.forEach((str, i) => {
      data[files[i]] = str;
    });
    // send data here
  }).catch((err) => {
    console.log(err);
  });

3

प्रोमिस की आधुनिक पद्धति के साथ एक और संस्करण। यह छोटा है कि वादा के आधार पर अन्य प्रतिक्रियाएँ:

const readFiles = (dirname) => {

  const readDirPr = new Promise( (resolve, reject) => {
    fs.readdir(dirname, 
      (err, filenames) => (err) ? reject(err) : resolve(filenames))
  });

  return readDirPr.then( filenames => Promise.all(filenames.map((filename) => {
      return new Promise ( (resolve, reject) => {
        fs.readFile(dirname + filename, 'utf-8',
          (err, content) => (err) ? reject(err) : resolve(content));
      })
    })).catch( error => Promise.reject(error)))
};

readFiles(sourceFolder)
  .then( allContents => {

    // handle success treatment

  }, error => console.log(error));

अच्छा और कुरकुरा! थैंक्स @Paul
अराजकता सेना

1

कोड के लिए विभिन्न वातावरण में सुचारू रूप से काम करने के लिए, path.resolve का उपयोग उन स्थानों पर किया जा सकता है जहां पथ में हेरफेर किया गया है। यहाँ कोड है जो बेहतर काम करता है।

पढ़ना हिस्सा:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
  fs.readdir(dirname, function(err, filenames) {
    if (err) {
      onError(err);
      return;
    }
    filenames.forEach(function(filename) {
      fs.readFile(path.resolve(dirname, filename), 'utf-8', function(err, content) {
        if (err) {
          onError(err);
          return;
        }
        onFileContent(filename, content);
      });
    });
  });
}

भंडारण भाग:

var data = {};
readFiles(path.resolve(__dirname, 'dirname/'), function(filename, content) {
  data[filename] = content;
}, function(error) {
  throw err;
});

1

मैंने अभी यह लिखा है और यह मेरे लिए अधिक साफ है:

const fs = require('fs');
const util = require('util');

const readdir = util.promisify(fs.readdir);
const readFile = util.promisify(fs.readFile);

const readFiles = async dirname => {
    try {
        const filenames = await readdir(dirname);
        console.log({ filenames });
        const files_promise = filenames.map(filename => {
            return readFile(dirname + filename, 'utf-8');
        });
        const response = await Promise.all(files_promise);
        //console.log({ response })
        //return response
        return filenames.reduce((accumlater, filename, currentIndex) => {
            const content = response[currentIndex];
            accumlater[filename] = {
                content,
            };
            return accumlater;
        }, {});
    } catch (error) {
        console.error(error);
    }
};

const main = async () => {

    const response = await readFiles(
        './folder-name',
    );
    console.log({ response });
};

आप responseअपनी आवश्यकता के अनुसार प्रारूप को संशोधित कर सकते हैं । responseइस कोड से प्रारूप तरह दिखेगा:

{
   "filename-01":{
      "content":"This is the sample content of the file"
   },
   "filename-02":{
      "content":"This is the sample content of the file"
   }
}


0

async / इंतजार

const { promisify } = require("util")
const directory = path.join(__dirname, "/tmpl")
const pathnames = promisify(fs.readdir)(directory)

try {
  async function emitData(directory) {
    let filenames = await pathnames
    var ob = {}
    const data = filenames.map(async function(filename, i) {
      if (filename.includes(".")) {
        var storedFile = promisify(fs.readFile)(directory + `\\${filename}`, {
          encoding: "utf8",
        })
        ob[filename.replace(".js", "")] = await storedFile
        socket.emit("init", { data: ob })
      }
      return ob
    })
  }

  emitData(directory)
} catch (err) {
  console.log(err)
}

जनरेटर के साथ कौन प्रयास करना चाहता है?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.