Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Herramienta de Inspección de Directorios | Creación de Aplicaciones de Consola con Node.js
Desarrollo Backend con Node.js y Express.js

Herramienta de Inspección de Directorios

Desliza para mostrar el menú

Este capítulo te presenta un desafío: crear una aplicación de consola avanzada llamada DirInspect Pro. Esta aplicación te permitirá analizar a fondo cualquier directorio y obtener estadísticas detalladas sobre sus archivos y subdirectorios.

Desafío

Imagina un escenario en el que debes navegar por un laberinto de carpetas que contienen archivos y datos cruciales. DirInspect Pro es tu aliado en este recorrido, proporcionando información integral sobre la estructura y el contenido del directorio.

La aplicación resultante

Prepárate para aprovechar las capacidades de DirInspect Pro. La aplicación te proporcionará información clave, como:

  • El número total de elementos;
  • El tamaño total de todos los elementos;
  • El nombre y tamaño del archivo más grande;
  • La lista detallada de nombres y tamaños de archivos individuales.

Dos caminos para elegir

Tienes dos caminos por delante.

  • El primero es afrontar este desafío directamente, perfeccionando tus habilidades sin ayuda;
  • El segundo es seguir una guía útil que garantiza tu éxito.

Elijas el camino que elijas, te espera una experiencia gratificante que culmina en la creación de una aplicación de consola atractiva y funcional.

Plan maestro

  • Paso 1: Importar los módulos requeridos;
  • Paso 2: Definir la función getStats;
  • Paso 3: Definir la función analyzeFile;
  • Paso 4: Definir la función analyzeDirectory;
  • Paso 5: Definir e invocar la función main;
  • Conclusión;
  • Código completo de la aplicación.

Paso 1: Importar los módulos requeridos

Para comenzar esta aventura, necesitas las herramientas adecuadas. Empieza importando dos módulos clave: fs.promises para gestionar el sistema de archivos de forma asíncrona y path para manejar rutas de archivos de manera eficiente.

const fs = require("fs").promises;
const path = require("path");
Descripción del código
expand arrow
  • Línea 1: importa el módulo incorporado fs. La propiedad .promises proporciona acceso a la API basada en promesas, permitiendo realizar operaciones de archivos de forma asíncrona utilizando async/await;
  • Línea 2: importa el módulo incorporado path. Este módulo ofrece utilidades para trabajar con rutas de archivos y directorios, incluyendo manipulación y normalización de rutas.

Paso 2: Definir la función getStats

La función asíncrona getStats recibe como argumento una ruta de archivo o directorio e intenta obtener sus estadísticas utilizando fs.stat.

  • Si tiene éxito, devuelve las estadísticas;
  • Si ocurre un error, muestra un mensaje de error y retorna null.
async function getStats(filePath) {
  try {
    const stats = await fs.stat(filePath);
    return stats;
  } catch (err) {
    console.error("Error getting stats:", err.message);
    return null;
  }
}
Descripción del código
expand arrow
  • Línea 1: declara una función asíncrona llamada getStats que acepta un parámetro filePath;
  • Líneas 2, 5: crea un bloque try...catch utilizado para el manejo de errores durante la operación asíncrona;
  • Línea 3: utiliza await fs.stat(filePath) para obtener información sobre el archivo especificado, como su tamaño, fecha de creación y otros metadatos;
  • Línea 4: retorna el objeto stats si la operación fs.stat() se completa correctamente;
  • Línea 6: muestra un mensaje de error en la consola usando console.error() si la operación falla;
  • Línea 7: retorna null para indicar que no se pudieron obtener las estadísticas del archivo.

Paso 3: Definir la función analyzeFile

La función analyzeFile utiliza la función getStats para obtener las estadísticas de un archivo. Si las estadísticas están disponibles (no son null), retorna un objeto que contiene el nombre del archivo (extraído usando path.basename) y su tamaño.

async function analyzeFile(filePath) {
  const stats = await getStats(filePath);
  if (!stats) return null;

  return {
    name: path.basename(filePath),
    size: stats.size,
  };
}
Descripción del código
expand arrow
  • Línea 1: declara una función asíncrona llamada analyzeFile que acepta un parámetro filePath;
  • Línea 2: utiliza await getStats(filePath) para obtener las estadísticas del archivo para la ruta proporcionada;
  • Línea 3: verifica si stats es falso. Si no se pudieron obtener las estadísticas, la función retorna null;
  • Líneas 5-8: crea y retorna un objeto que contiene el nombre y el tamaño del archivo. El nombre del archivo se extrae usando path.basename(filePath), mientras que el tamaño se obtiene de stats.size.

Paso 4: Definir la función analyzeDirectory

La función analyzeDirectory escanea un directorio y recopila estadísticas completas sobre su contenido. Funcionamiento: lee todos los elementos dentro del directorio usando fs.readdir. Para cada elemento:

  • Construye la ruta completa con path.join;
  • Utiliza getStats para detectar si es un archivo o una carpeta;
  • Si es un archivo:
    • Llama a analyzeFile para obtener { name, size };
    • Actualiza los totales, el archivo más grande y la lista de archivos.
  • Si es un directorio:
    • Llama recursivamente a analyzeDirectory;
    • Fusiona los resultados en las estadísticas actuales.
async function analyzeDirectory(directoryPath) {
  let totalItems = 0;
  let totalFiles = 0;
  let totalSize = 0;
  let largestFile = { name: "", size: 0 };
  let fileList = [];

  try {
    const items = await fs.readdir(directoryPath);

    for (const item of items) {
      const itemPath = path.join(directoryPath, item);
      const stats = await getStats(itemPath);
      if (!stats) continue;

      totalItems++;

      if (stats.isFile()) {
        const fileInfo = await analyzeFile(itemPath);
        if (!fileInfo) continue;

        totalFiles++;
        totalSize += fileInfo.size;

        if (fileInfo.size > largestFile.size) {
          largestFile = fileInfo;
        }

        fileList.push(fileInfo);
      } else if (stats.isDirectory()) {
        const subDirectoryStats = await analyzeDirectory(itemPath);

        totalItems += subDirectoryStats.totalItems;
        totalFiles += subDirectoryStats.totalFiles;
        totalSize += subDirectoryStats.totalSize;

        if (subDirectoryStats.largestFile.size > largestFile.size) {
          largestFile = subDirectoryStats.largestFile;
        }

        fileList = fileList.concat(subDirectoryStats.fileList);
      }
    }

    return {
      totalItems,
      totalFiles,
      totalSize,
      largestFile,
      fileList
    };
  } catch (err) {
    console.error("Error analyzing directory contents:", err.message);
    return {
      totalItems: 0,
      totalFiles: 0,
      totalSize: 0,
      largestFile: { name: "", size: 0 },
      fileList: []
    };
  }
}
Descripción del código
expand arrow
  • Línea 1: declara una función asíncrona llamada analyzeDirectory que acepta un parámetro directoryPath;

  • Líneas 2-6: inicializan variables utilizadas para almacenar estadísticas del directorio, incluyendo el total de elementos, total de archivos, tamaño total, el archivo más grande y una lista de archivos analizados;

  • Línea 8: inicia un bloque try para manejar posibles errores del sistema de archivos;

  • Línea 9: lee el contenido del directorio usando fs.readdir() y almacena el resultado en el arreglo items;

  • Línea 11: inicia un bucle for...of para iterar sobre cada elemento del directorio;

  • Línea 12: crea la ruta completa para el elemento actual usando path.join();

  • Línea 13: obtiene las estadísticas para el elemento actual usando getStats();

  • Línea 14: omite el elemento actual si no se pudieron obtener sus estadísticas;

  • Línea 16: incrementa totalItems por cada archivo o directorio procesado correctamente;

  • Líneas 18-29: gestionan el procesamiento de archivos:

  • Línea 19: llama a analyzeFile() para obtener el nombre y tamaño del archivo;

  • Línea 20: omite el archivo si falla el análisis;

    • Líneas 22-23: actualizan el conteo total de archivos y el tamaño acumulado;
    • Líneas 25-27: actualizan largestFile si el archivo actual es más grande que el previamente registrado;
  • Línea 29: agrega la información del archivo a fileList;

  • Líneas 30-42: gestionan el procesamiento de directorios:

  • Línea 31: llama recursivamente a analyzeDirectory() para el subdirectorio;

    • Líneas 33-35: fusionan las estadísticas del subdirectorio en los totales actuales;
    • Líneas 37-39: actualizan largestFile si el subdirectorio contiene un archivo más grande;
  • Línea 41: fusiona las listas de archivos usando concat();

  • Líneas 45-50: retornan un objeto que contiene las estadísticas finales del directorio;

  • Líneas 52-62: gestionan errores registrando un mensaje y retornando un objeto de estadísticas por defecto.

Paso 5: Definir la función main e invocarla

La función main es el punto de entrada del script. Especifica la ruta del directorio a analizar (en este caso, ./docs), llama a la función analyzeDirectory para obtener las estadísticas del directorio y su contenido, y luego muestra la información recopilada. La función imprime:

  • El número total de elementos;
  • El número total de archivos;
  • El tamaño total;
  • Los detalles sobre el archivo más grande;
  • La lista de archivos en el directorio.
async function main() {
  const directoryPath = "./docs";
  const directoryStats = await analyzeDirectory(directoryPath);

  console.log("Directory Analysis:");
  console.log("Total items:", directoryStats.totalItems);
  console.log("Total files:", directoryStats.totalFiles);
  console.log("Total size (bytes):", directoryStats.totalSize);
  console.log(
    "Largest file:",
    directoryStats.largestFile.name,
    "Size:",
    directoryStats.largestFile.size,
    "bytes"
  );

  console.log("\nFile List:");
  for (const file of directoryStats.fileList) {
    console.log(file.name, "Size:", file.size, "bytes");
  }
}

main();
Descripción del código
expand arrow
  • Línea 1: declara una función asíncrona llamada main;

  • Línea 2: define la variable directoryPath, que almacena la ruta al directorio que será analizado;

  • Línea 3: llama a analyzeDirectory() con el directoryPath especificado y almacena el resultado en la variable directoryStats usando await;

  • Líneas 5-17: muestran las estadísticas calculadas del directorio usando console.log(), incluyendo el número total de elementos, archivos totales, tamaño total e información sobre el archivo más grande;

  • Líneas 18-20: recorren el arreglo fileList almacenado en directoryStats;

  • registran el nombre y tamaño de cada archivo en el directorio;

  • Línea 23: llama a la función main() para iniciar el proceso de análisis.

Código completo de la aplicación

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

async function getStats(filePath) {
  try {
    const stats = await fs.stat(filePath);
    return stats;
  } catch (err) {
    console.error("Error getting stats:", err.message);
    return null;
  }
}

async function analyzeFile(filePath) {
  const stats = await getStats(filePath);
  if (!stats) return null;

  return {
    name: path.basename(filePath),
    size: stats.size
  };
}

async function analyzeDirectory(directoryPath) {
  let totalItems = 0;
  let totalFiles = 0;
  let totalSize = 0;
  let largestFile = { name: "", size: 0 };
  let fileList = [];

  try {
    const items = await fs.readdir(directoryPath);

    for (const item of items) {
      const itemPath = path.join(directoryPath, item);
      const stats = await getStats(itemPath);
      if (!stats) continue;

      totalItems++;

      if (stats.isFile()) {
        const fileInfo = await analyzeFile(itemPath);
        if (!fileInfo) continue;

        totalFiles++;
        totalSize += fileInfo.size;

        if (fileInfo.size > largestFile.size) {
          largestFile = fileInfo;
        }

        fileList.push(fileInfo);
      } else if (stats.isDirectory()) {
        const subDirectoryStats = await analyzeDirectory(itemPath);

        totalItems += subDirectoryStats.totalItems;
        totalFiles += subDirectoryStats.totalFiles;
        totalSize += subDirectoryStats.totalSize;

        if (subDirectoryStats.largestFile.size > largestFile.size) {
          largestFile = subDirectoryStats.largestFile;
        }

        fileList = fileList.concat(subDirectoryStats.fileList);
      }
    }

    return {
      totalItems,
      totalFiles,
      totalSize,
      largestFile,
      fileList
    };
  } catch (err) {
    console.error("Error analyzing directory contents:", err.message);
    return {
      totalItems: 0,
      totalFiles: 0,
      totalSize: 0,
      largestFile: { name: "", size: 0 },
      fileList: []
    };
  }
}

async function main() {
  const directoryPath = "./docs";
  const directoryStats = await analyzeDirectory(directoryPath);

  console.log("Directory Analysis:");
  console.log("Total items:", directoryStats.totalItems);
  console.log("Total files:", directoryStats.totalFiles);
  console.log("Total size (bytes):", directoryStats.totalSize);

  console.log(
    "Largest file:",
    directoryStats.largestFile.name,
    "Size:",
    directoryStats.largestFile.size,
    "bytes"
  );

  console.log("\nFile List:");
  for (const file of directoryStats.fileList) {
    console.log(file.name, "Size:", file.size, "bytes");
  }
}

main();
¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 2. Capítulo 10

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

Sección 2. Capítulo 10
some-alt