Exercise - Work with the file system

Completed

You can use Node.js to find and return information about files and folders.

Tailwind Traders has many physical stores all over the world. Each night, these stores create a file called sales.json that contains the total for all their sales for the previous day. These files are organized in folders by store ID.

In this exercise, you'll write a Node.js program that can search for files called sales.json in a folder.

Sign in to the sandbox

Activate the Microsoft Learn sandbox by selecting Activate Sandbox at the top of this page.

Set up the environment

Run the following command in Azure Cloud Shell on the right to ensure that you're working with the most current version of Node.js:

source <(curl -Ls https://aka.ms/install-node-lts)

Clone the project

  1. Run the following command to clone the example project for this module:

    git clone https://github.com/MicrosoftDocs/node-essentials && cd node-essentials/nodejs-files
    
  2. Open the Cloud Shell editor by running the following command in Cloud Shell.

    code .
    
  3. Expand the stores folder and each of the numbered folders inside.

    Screenshot that shows the project folder structure.

Find the sales.json files

You need to find all the files in only the topmost location: the stores folder.

Include the fs module

  1. Select the index.js file to open it in the editor.

  2. Include the fs module at the top of the file.

    const fs = require("fs").promises;
    
  3. Create a main method. This method will be the entry point for your code. The last line of code in this file will invoke the main method.

    const fs = require("fs").promises;
    
    async function main() {}
    
    main();
    

Write a method to find the sales.json files

  1. Create a new method called findSalesFiles that takes a folderName parameter.

    async function findSalesFiles(folderName) {
      // FIND SALES FILES
    }
    
  2. Add an array at the top, which will hold the paths to all the sales files that the program finds.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      // FIND SALES FILES
    }
    
  3. Create a method within this function called findFiles, which also takes a folderName parameter.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      async function findFiles(folderName) {
        // FIND SALES FILES
      }
    }
    

    This new method findFiles is created inside the main findSalesMethod method so that it can run as many times as necessary to find all the sales files and populate the salesFiles array. The folderName value is the path to the current folder.

  4. Inside the findFiles method, read the currentFolder path with the readdirsync method.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      async function findFiles(folderName) {
        // read all the items in the current folder
        const items = await fs.readdir(folderName, { withFileTypes: true });
    
        // FIND SALES FILES
      }
    }
    
  5. Add a block to loop over each item returned from the readdirsync method.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      async function findFiles(folderName) {
        // read all the items in the current folder
        const items = await fs.readdir(folderName, { withFileTypes: true });
    
        // iterate over each found item
        for (item of items) {
          // FIND SALES FILES
        }
      }
    }
    
  6. Add an if statement to determine if the item is a file or a directory.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      async function findFiles(folderName) {
        // read all the items in the current folder
        const items = await fs.readdir(folderName, { withFileTypes: true });
    
        // iterate over each found item
        for (item of items) {
          if (item.isDirectory()) {
            // FIND SALES FILES IN THIS FOLDER
          } else {
            // FIND SALES FILES
          }
        }
      }
    }
    
  7. If the item is a directory, call the findFiles method again, passing in the path to the item. If it's not, add a check to make sure the item name matches sales.json.

    async function findSalesFiles(folderName) {
      // this array will hold sales files as they are found
      let salesFiles = [];
    
      async function findFiles(folderName) {
        // read all the items in the current folder
        const items = await fs.readdir(folderName, { withFileTypes: true });
    
        // iterate over each found item
        for (item of items) {
          if (item.isDirectory()) {
            // search this directory for files (this is recursion!)
            await findFiles(`${folderName}/${item.name}`);
          } else {
            // Make sure the discovered file is a sales.json file
            if (item.name === "sales.json") {
              // store the file path in the salesFiles array
              salesFiles.push(`${folderName}/${item.name}`);
            }
          }
        }
      }
      await findFiles(folderName);
      return salesFiles;
    }
    
  8. Call this new findSaleFiles function from the main method. Pass in the stores folder name as the location to search for files.

    async function main() {
      const salesFiles = await findSalesFiles("stores");
      console.log(salesFiles);
    }
    
  9. Press Ctrl-S to save the file, and press Ctrl-Q to close the editor.

Run the program

  1. Enter the following command into Cloud Shell to run the program.

    node index.js
    
  2. The program should show the following output.

    [
     'stores/201/sales.json',
     'stores/202/sales.json',
     'stores/203/sales.json',
     'stores/204/sales.json',
    ]
    

Excellent! You've successfully written a command-line program that will traverse any directory and find all the sales.json files inside.

However, the way that the path to subfolders was constructed in this example is a little clumsy because it requires concatenating strings together. Also, you might run into issues on other operating systems (like Windows) that use different path separators.

In the next section, you'll learn how to construct paths that work across operating systems by using the path module.

Got stuck?

If you got stuck at any point in this exercise, here's the completed code. Remove everything in index.js and replace it with this solution.

const fs = require("fs");

async function findSalesFiles(folderName) {
  // this array will hold sales files as they are found
  let salesFiles = [];

  async function findFiles(folderName) {
    // read all the items in the current folder
    const items = await fs.readdirSync(folderName, { withFileTypes: true });

    // iterate over each found item
    for (item of items) {
      // if the item is a directory, it will need to be searched for files
      if (item.isDirectory()) {
        // search this directory for files (this is recursion!)
        await findFiles(`${folderName}/${item.name}`);
      } else {
        // Make sure the discovered file is a sales.json file
        if (item.name === "sales.json") {
          // store the file path in the salesFiles array
          salesFiles.push(`${folderName}/${item.name}`);
        }
      }
    }
  }

  // find the sales files
  await findFiles(folderName);

  // return the array of found file paths
  return salesFiles;
}

async function main() {
  const salesFiles = await findSalesFiles("stores");
  console.log(salesFiles);
}

main();