Ejercicio: Trabajar con el sistema de archivos

Completado

Tailwind Traders tiene muchas tiendas físicas repartidas por todo el mundo. Cada noche, las tiendas crean un archivo denominado sales.json que contiene el total de todas las ventas del día anterior. Estos archivos se organizan en carpetas nombradas por id. de tienda.

En este ejercicio, va a escribir un programa de Node.js que busca archivos llamados sales.json en una carpeta.

Abrir el proyecto en el contenedor de desarrollo

  1. Inicie el proceso para crear una nueva instancia de GitHub Codespace en la rama main del repositorio de GitHub MicrosoftDocs/node-essentials.

  2. En la página Crear codespace, revise las opciones de configuración de codespace y, después, seleccione Crear nuevo codespace

    Screenshot of the confirmation screen before creating a new codespace.

  3. Espere a que se inicie Codespace. Este proceso de startup puede tardar unos minutos.

  4. Abra un nuevo terminal en el codespace.

    Sugerencia

    Puede usar el menú principal para ir a la opción de menú Terminal y, a continuación, seleccionar la opción Nuevo terminal.

    Screenshot of the codespaces menu option to open a new terminal.

  5. Compruebe que Node.js está instalado en el entorno:

    node --version
    

    El contenedor de desarrollo usa una versión Node.js LTS, como v20.5.1. La versión exacta podría ser diferente.

  6. Los demás ejercicios de este proyecto tienen lugar en el contexto de este contenedor de desarrollo.

Búsqueda de los archivos sales.json

La tarea es buscar todos los archivos de la carpeta stores.

Expanda la carpeta stores y cada una de las carpetas numeradas en su interior.

Screenshot that shows the project folder structure.

Inclusión del módulo fs

  1. En la subcarpeta ./nodejs-files, cree un archivo index.js para abrirlo en el editor.

  2. En la parte superior del archivo, agregue el código siguiente para incluir el módulo fs en el archivo.

    const fs = require("fs").promises;
    
  3. A continuación, cree la función main, que es el punto de entrada del código. La última línea de código de este archivo invoca al método main.

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

    Este es el código reutilizable de CommonJS típico para llamar a una función asincrónica.

Escribir una función para buscar los archivos sales.json

  1. Cree una función denominada findSalesFiles que tome un parámetro folderName.

    async function findSalesFiles(folderName) {
      // FIND SALES FILES
    }
    
  2. Dentro de la función findSalesFiles, agregue el código siguiente para completar estas tareas:

    • (1) Agregue una matriz al inicio que contenga las rutas de acceso a todos los archivos de ventas que encuentre el programa.
    • (2) Lea currentFolder con el método readdir.
    • (3) Agregue un bloque para recorrer en bucle cada elemento devuelto desde el método readdir mediante el bucle asincrónico for...of.
    • (4) Agregue una instrucción if para saber si el elemento es un archivo o un directorio.
    • (5) Si el elemento es un directorio, llame recursivamente a la función findSalesFiles de nuevo, pasando la ruta de acceso al elemento.
    • (6) Si no lo es, agregue una comprobación para asegurarse de que el nombre del elemento coincide con sales.json.
    async function findSalesFiles(folderName) {
    
       // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
       let results = [];
    
       // (2) Read the currentFolder with the `readdir` method. 
       const items = await fs.readdir(folderName, { withFileTypes: true });
    
       // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
       for (const item of items) {
    
         // (4) Add an `if` statement to determine if the item is a file or a directory. 
         if (item.isDirectory()) {
    
           // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
           const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
           results = results.concat(resultsReturned);
         } else {
           // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
           if (item.name === "sales.json") {
             results.push(`${folderName}/${item.name}`);
           }
         }
       }
    
       return results;
    }
    
  3. Llame a esta función nueva de findSaleFiles desde el método main. Pase el nombre de la carpeta stores como la ubicación en la que buscar archivos.

     async function main() {
       const results = await findSalesFiles("stores");
       console.log(results);
     }
    
  4. La aplicación completa tiene el siguiente aspecto:

    const fs = require("fs").promises;
    
    async function findSalesFiles(folderName) {
    
      // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
      let results = [];
    
      // (2) Read the currentFolder with the `readdir` method. 
      const items = await fs.readdir(folderName, { withFileTypes: true });
    
      // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
      for (const item of items) {
    
        // (4) Add an `if` statement to determine if the item is a file or a directory. 
        if (item.isDirectory()) {
    
          // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
          const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
          results = results.concat(resultsReturned);
        } else {
          // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
          if (item.name === "sales.json") {
            results.push(`${folderName}/${item.name}`);
          }
        }
      }
    
      return results;
    }
    
    async function main() {
      const results = await findSalesFiles("stores");
      console.log(results);
    }
    
    main();
    

Ejecutar el programa

  1. Escriba el siguiente comando en el terminal para ejecutar el programa.

    node index.js
    
  2. El programa debe mostrar la salida siguiente.

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

Excelente. Ha escrito correctamente un programa de línea de comandos que puede recorrer cualquier directorio y encontrar todos los archivos sales.json que haya en ellos.

A pesar de ello, el modo en que se ha construido la ruta de acceso a las subcarpetas en este ejemplo es un poco engorroso, porque requiere concatenar cadenas. Además, es posible que surjan incidencias en otros sistemas operativos (como Windows) que usan separadores de ruta de acceso diferentes.

En la sección siguiente, obtendremos información sobre cómo construir rutas de acceso que funcionen en varios sistemas operativos mediante el módulo path.

¿Se ha bloqueado?

Si se ha bloqueado en algún momento de este ejercicio, aquí tiene el código completo. Quite todo en index.js y reemplácelo por esta solución.

const fs = require("fs").promises;

async function findSalesFiles(folderName) {

  // (1) Add an array at the top, to hold the paths to all the sales files that the program finds.
  let results = [];

  // (2) Read the currentFolder with the `readdir` method. 
  const items = await fs.readdir(folderName, { withFileTypes: true });

  // (3) Add a block to loop over each item returned from the `readdir` method using the asynchronous `for...of` loop. 
  for (const item of items) {

    // (4) Add an `if` statement to determine if the item is a file or a directory. 
    if (item.isDirectory()) {

      // (5) If the item is a directory, recursively call the function `findSalesFiles` again, passing in the path to the item. 
      const resultsReturned = await findSalesFiles(`${folderName}/${item.name}`);
      results = results.concat(resultsReturned);
    } else {
      // (6) If it's not a directory, add a check to make sure the item name matches *sales.json*.
      if (item.name === "sales.json") {
        results.push(`${folderName}/${item.name}`);
      }
    }
  }

  return results;
}

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

main();