Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading all files in a directory, store them in objects, and send the object

Tags:

node.js

I do not know if this is possible, but here goes. And working with callbacks makes it even more difficult.

I have a directory with html files that I want to send back to the client in Object chunks with node.js and socket.io.

All my files are in /tmpl

So socket needs to read all the files in /tmpl.

for each file it has to store the data in an object with the filename as the key, and the content as the value.

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

The final callback is also wrong. It has to be called when all the files in the directory are done.

But I do not know how to create the code, anyone know if this is possibel?

like image 207
Saif Bechan Avatar asked Apr 06 '12 21:04

Saif Bechan


People also ask

How do I read all files in a directory in Python?

To get a list of all the files and folders in a particular directory in the filesystem, use os. listdir() in legacy versions of Python or os. scandir() in Python 3.

How can you read the contents of a directory while also returning the file type information?

readdir() method is used to asynchronously read the contents of a given directory. The callback of this method returns an array of all the file names in the directory. The options argument can be used to change the format in which the files are returned from the method.


2 Answers

So, there are three parts. Reading, storing and sending.

Here's the reading part:

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

Here's the storing part:

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

The sending part is up to you. You may want to send them one by one or after reading completion.

If you want to send files after reading completion you should either use sync versions of fs functions or use promises. Async callbacks is not a good style.

Additionally you asked about stripping an extension. You should proceed with questions one by one. Nobody will write a complete solution just for you.

like image 141
stewe Avatar answered Sep 18 '22 13:09

stewe


This is a modern Promise version of the previous one, using a Promise.all approach to resolve all promises when all files have been read:

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

How to Use It:

Just as simple as doing:

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

Supposed that you have another list of folders you can as well iterate over this list, since the internal promise.all will resolve each of then asynchronously:

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

How it Works

The promiseAll does the magic. It takes a function block of signature function(item,index,resolve,reject), where item is the current item in the array, index its position in the array, and resolve and reject the Promise callback functions. Each promise will be pushed in a array at the current index and with the current item as arguments through a anonymous function call:

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

Then all promises will be resolved:

return Promise.all(promises); 
like image 37
loretoparisi Avatar answered Sep 21 '22 13:09

loretoparisi