Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Ferramenta de Inspeção de Diretórios | Construindo Aplicações de Console com Node.js
Desenvolvimento Backend com Node.js e Express.js

Ferramenta de Inspeção de Diretórios

Deslize para mostrar o menu

Este capítulo apresenta um desafio: criar um aplicativo de console avançado chamado DirInspect Pro. Este aplicativo permitirá que você analise detalhadamente qualquer diretório e obtenha estatísticas relevantes sobre seus arquivos e subdiretórios.

Desafio

Imagine um cenário em que você precisa navegar por um labirinto de pastas contendo arquivos e dados essenciais. O DirInspect Pro é seu aliado nessa jornada, fornecendo uma visão abrangente da estrutura e do conteúdo do diretório.

O Aplicativo Resultante

Prepare-se para utilizar os recursos do DirInspect Pro. O aplicativo fornecerá informações essenciais, como:

  • O número total de itens;
  • O tamanho agregado de todos os itens;
  • O nome e o tamanho do maior arquivo;
  • A lista detalhada dos nomes e tamanhos de cada arquivo individualmente.

Dois Caminhos para Escolher

Você tem dois caminhos à frente.

  • O primeiro é enfrentar esse desafio diretamente, aprimorando suas habilidades sem orientação;
  • O segundo é seguir um guia útil que garante seu sucesso.

Independentemente do caminho escolhido, você terá uma jornada recompensadora que culmina na criação de um aplicativo de console envolvente e funcional.

Plano Mestre

  • Etapa 1: Importar módulos necessários;
  • Etapa 2: Definir a função getStats;
  • Etapa 3: Definir a função analyzeFile;
  • Etapa 4: Definir a função analyzeDirectory;
  • Etapa 5: Definir e invocar a função main;
  • Conclusão;
  • Código completo do aplicativo.

Etapa 1: Importar módulos necessários

Para iniciar esta jornada, é preciso ter as ferramentas certas. Comece importando dois módulos principais: fs.promises para gerenciar o sistema de arquivos de forma assíncrona e path para manipular caminhos de arquivos de maneira eficiente.

const fs = require("fs").promises;
const path = require("path");
Descrição do código
expand arrow
  • Linha 1: importa o módulo nativo fs. A propriedade .promises fornece acesso à API baseada em promessas, permitindo operações assíncronas de arquivos utilizando async/await;
  • Linha 2: importa o módulo nativo path. Este módulo oferece utilitários para trabalhar com caminhos de arquivos e diretórios, incluindo manipulação e normalização de caminhos.

Etapa 2: Definir a função getStats

A função assíncrona getStats recebe um caminho de arquivo ou diretório como argumento e tenta obter suas estatísticas usando fs.stat.

  • Se for bem-sucedida, retorna as estatísticas;
  • Se ocorrer um erro, registra uma mensagem de erro e 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;
  }
}
Descrição do código
expand arrow
  • Linha 1: declara uma função assíncrona chamada getStats que aceita um parâmetro filePath;
  • Linhas 2, 5: cria um bloco try...catch utilizado para tratamento de erros durante a operação assíncrona;
  • Linha 3: utiliza await fs.stat(filePath) para obter informações sobre o arquivo especificado, como seu tamanho, data de criação e outros metadados;
  • Linha 4: retorna o objeto stats se a operação fs.stat() for concluída com sucesso;
  • Linha 6: registra uma mensagem de erro no console usando console.error() caso a operação falhe;
  • Linha 7: retorna null para indicar que as estatísticas do arquivo não puderam ser obtidas.

Etapa 3: Definir a função analyzeFile

A função analyzeFile utiliza a função getStats para obter estatísticas de um arquivo. Se as estatísticas estiverem disponíveis (diferente de null), retorna um objeto contendo o nome do arquivo (extraído usando path.basename) e seu tamanho.

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

  return {
    name: path.basename(filePath),
    size: stats.size,
  };
}
Descrição do código
expand arrow
  • Linha 1: declara uma função assíncrona chamada analyzeFile que recebe um parâmetro filePath;
  • Linha 2: utiliza await getStats(filePath) para obter as estatísticas do arquivo para o caminho fornecido;
  • Linha 3: verifica se stats é falso. Se as estatísticas não puderem ser obtidas, a função retorna null;
  • Linhas 5-8: cria e retorna um objeto contendo o nome e o tamanho do arquivo. O nome do arquivo é extraído usando path.basename(filePath), enquanto o tamanho é obtido de stats.size.

Etapa 4: Definir a função analyzeDirectory

A função analyzeDirectory examina um diretório e reúne estatísticas completas sobre seu conteúdo. Como funciona: ela lê todos os itens dentro do diretório usando fs.readdir. Para cada item:

  • Constrói o caminho completo com path.join;
  • Usa getStats para detectar se é um arquivo ou uma pasta;
  • Se for um arquivo:
    • Chama analyzeFile para obter { name, size };
    • Atualiza totais, maior arquivo e a lista de arquivos.
  • Se for um diretório:
    • Chama recursivamente analyzeDirectory;
    • Mescla os resultados nas estatísticas atuais.
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: []
    };
  }
}
Descrição do código
expand arrow
  • Linha 1: declara uma função assíncrona chamada analyzeDirectory que recebe um parâmetro directoryPath;

  • Linhas 2-6: inicializa variáveis usadas para armazenar estatísticas do diretório, incluindo total de itens, total de arquivos, tamanho total, o maior arquivo e uma lista de arquivos analisados;

  • Linha 8: inicia um bloco try para tratar possíveis erros do sistema de arquivos;

  • Linha 9: lê o conteúdo do diretório usando fs.readdir() e armazena o resultado no array items;

  • Linha 11: inicia um loop for...of para iterar por cada item no diretório;

  • Linha 12: cria o caminho completo para o item atual usando path.join();

  • Linha 13: obtém as estatísticas para o item atual usando getStats();

  • Linha 14: ignora o item atual se as estatísticas não puderem ser obtidas;

  • Linha 16: incrementa totalItems para cada arquivo ou diretório processado com sucesso;

  • Linhas 18-29: tratam o processamento de arquivos:

  • Linha 19: chama analyzeFile() para obter o nome e o tamanho do arquivo;

  • Linha 20: ignora o arquivo se a análise falhar;

    • Linhas 22-23: atualiza o total de arquivos e o tamanho acumulado dos arquivos;
    • Linhas 25-27: atualiza largestFile se o arquivo atual for maior que o anteriormente registrado;
  • Linha 29: adiciona as informações do arquivo à fileList;

  • Linhas 30-42: tratam o processamento de diretórios:

  • Linha 31: chama recursivamente analyzeDirectory() para o subdiretório;

    • Linhas 33-35: mescla as estatísticas do subdiretório nos totais atuais;
    • Linhas 37-39: atualiza largestFile se o subdiretório contiver um arquivo maior;
  • Linha 41: mescla as listas de arquivos usando concat();

  • Linhas 45-50: retornam um objeto contendo as estatísticas finais do diretório;

  • Linhas 52-62: tratam erros registrando uma mensagem e retornando um objeto de estatísticas padrão.

Passo 5: Definir a Função main e Invocar

A função main é o ponto de entrada do script. Ela especifica o caminho do diretório a ser analisado (neste caso, ./docs), chama a função analyzeDirectory para obter as estatísticas do diretório e de seu conteúdo, e então exibe as informações coletadas. A função imprime:

  • O número total de itens;
  • O número total de arquivos;
  • O tamanho total;
  • Os detalhes sobre o maior arquivo;
  • A lista de arquivos no diretório.
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();
Descrição do código
expand arrow
  • Linha 1: declara uma função assíncrona chamada main;

  • Linha 2: define a variável directoryPath, que armazena o caminho do diretório que será analisado;

  • Linha 3: chama analyzeDirectory() com o directoryPath especificado e armazena o resultado na variável directoryStats usando await;

  • Linhas 5-17: exibem as estatísticas calculadas do diretório usando console.log(), incluindo o número total de itens, total de arquivos, tamanho total e informações sobre o maior arquivo;

  • Linhas 18-20: percorrem o array fileList armazenado em directoryStats;

  • exibem o nome e o tamanho de cada arquivo no diretório;

  • Linha 23: chama a função main() para iniciar o processo de análise.

Código Completo do Aplicativo

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();
Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 10

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Seção 2. Capítulo 10
some-alt