Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store fs.stat while looping through files into an array, in Node JS

I'm looping through files in a directory and storing the file details to an array data. The following code populates the array if I don't attempt to run fs.stat to get things like the file create/edit date:

fs.readdir('../src/templates', function (err, files) {
     if (err) {
        throw err;
      }
      var data = [];
      files
      .forEach(function (file) {
        try {
          fs.stat('../src/templates/'+file,(error,stats) => {
            data.push({ Name : file,Path : path.join(query, file)  });
          });
        } catch(e) {
          console.log(e);
        }

      });

      res.json(data);
  });
});

If I move the data.push(...) outside the fs.stat the array returns with the file data. Inside the fs.stat it returns empty. I assume this is an asynchronous issue in that the for loop is running and finishing before fs.stat runs.

I'm thinking I need to use a promise here but unsure.

like image 423
dcp3450 Avatar asked Feb 27 '18 20:02

dcp3450


People also ask

Which FS module method can be used to get an array of files?

readdir() Method. The fs. 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.

What is __ Dirname in node?

__dirname: It is a local variable that returns the directory name of the current module. It returns the folder path of the current JavaScript file. Difference between process.cwd() vs __dirname in Node.js is as follows: process.cwd()

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

Method 1: Using fs. readdirSync() is a method that is available in the file system module of Node. js. It is used for reading the contents of a directory. It returns an array of file paths, buffers, or fs.

What is the fs module in Node JS?

The promises object of the fs module was introduced in Node.js version 10, so some earlier versions still call the module experimental. This warning was removed when the API became stable in version 12.6. Now that you’ve read a file with the fs module, you will next create a file and write text to it.

What happens if I don’t specify a filesystem flag in Node JS?

If you don’t specify a flag, it defaults to w, which creates a new file if none exists or overwrites a file if it already exists. You can learn more about filesystem flags in the Node.js documentation. To complete your script, use these functions. Add the following highlighted lines at the end of the file:

How to keep track of a grocery bill in Node JS?

You will create a CSV file in Node.js that keeps track of a grocery bill. The first time you write the file, you will create the file and add the headers. The second time, you will append data to the file. You will continue to use async/await syntax as you create two functions. The first function will be to make the CSV file.

What is a flag in Node JS?

Flags tell Node.js how to interact with the file on the system. By using the flag a, you are telling Node.js to append to the file, not overwrite it. If you don’t specify a flag, it defaults to w, which creates a new file if none exists or overwrites a file if it already exists.


2 Answers

If you want or need to be asynchronous:

const fs = require("fs");
const path = require("path");
const { promisify } = require("util");

const asyncStat = promisify(fs.stat);

fs.readdir('../src/templates', async function(err, files) {
  if (err) {
    throw err;
  }
  const data = await Promise.all(files.map(async function(file) {
    try {
      const stats = await asyncStat('../src/templates/' + file);
      return { Name: file, Path: path.join(query, file), stats };
    } catch (e) {
      console.log(e);
    }
  }));
  res.json(data);
});

Note that I used map instead of forEach and then awaited all Promises (async makes function return a promise). I also needed to change fs.stat to use promise with util.promisify.

like image 142
barnski Avatar answered Oct 18 '22 17:10

barnski


You're right about the issue being in the asynchronous call. You could use a promise, or you could use fs.statSync(...), which returns a fs.Stats object and operates synchonously.

files.forEach(function (file) {
    try {
        var fileStats = fs.statSync('../src/templates/' + file);
        data.push({ 
            Name : file,
            Path : path.join(query, file)  
        });
    } catch(e) {
        console.log(e);
    }
});
like image 37
Bucket Avatar answered Oct 18 '22 15:10

Bucket