Módulos Internos (Core Modules) - Parte 2
Seja bem vindo a parte dois dos módulos internos 😁
Na lição passada, você aprendeu um pouco mais sobre:
Por hora, vamos continuar nosso processo de aprendizado conhecendo outros módulos como:
events
para escutar eventos na aplicação,fs (file system)
para manipulação de arquivos,url
para manipulação e tratamento de urls,os
para interagir com o sistema operacional.
Vamos nessa? 😉
Arquivos da lição
Os arquivos que veremos durante o decorrer desta lição, podem ser encontrados nos links abaixo:
Módulo events
No mundo do NodeJS, nós temos acesso a um módulo chamado de events
, que fornece uma infraestrutura para se trabalhar com eventos que acontecem dentro da sua aplicação.
Eventos estes capazes de lidar com operações assíncronas, permitindo a escuta e manipulação desses eventos de maneira eficiente, e isso inclui:
- Interações do usuário,
- Leitura de arquivos,
- Conexões em rede,
- Além de gatilhos que podemos acionar em algum ponto durante a execução do nosso código.
É importante ressaltar que a classe principal que existe por trás do módulo events
, é a conhecida como Event Emitter
, onde ela comporta de forma similar aos eventos do navegador (Cliente Side).
Sabendo que o módulo events possui uma classe por trás, devemos saber que não basta apenas importar o módulo e usar seus métodos (como vinhamos fazendo anteriormente), como também precisarémos instanciar a classe.
Vamos ver como tudo isso funciona na prática 🤓
Como de praxe, vamos começar criando um arquivo chamado de app.js
dentro da pasta do seu projeto.
Em importar o módulo do Event Emitter
:
/* Aplicação de Testes (app.js) */
const eventEmitter = require('events');
Como dito anteriormente, o módulo em sí é uma classe do Javascript, e como toda boa classe, ela precisa ser instanciada para ser usada, logo:
/* Aplicação de Testes (app.js) */
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();//Instancia a classe Event Emitter
Legal, para começar a usar o Event Emitter
primeiro nós temos que registrar um evento a ser escutado.
Vamos supor, que queriamos mostrar uma mensagem no console toda vez que um evento chamado runner
seja executado.
Para isso, precisamos fazer o uso do método on
presente na classe do Event Emitter
da seguinte forma:
/* Aplicação de Testes (app.js) */
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();//Instancia a classe Event Emitter
eventEmitter.on('runner', () => {
console.log('Você já viu o filme do Blade Runner 2044?');
});
Traduzindo para o bom português, o on
significa quando, sendo assim: "Quando o evento chamado runner for executado, eu vou executar esse bloco, que por sua vez vai mostrar uma mensagem no console".
Para executar esse evento, nós fazemos o uso de um outro método da classe do Event Emitter
chamado de emit()
.
Ele é responsável por emitir um determinado evento ao sistema, e se o nome do evento existir, bem, o bloco do on
é acionado, caso contrário, nada acontece.
/* Aplicação de Testes (app.js) */
const EventEmitter = require('events');
const eventEmitter = new EventEmitter();//Instancia a classe Event Emitter
eventEmitter.on('runner', () => {
console.log('Você já viu o filme do Blade Runner 2044?');
});
console.log('Eu sempre quis te fazer uma pergunta...');
eventEmitter.emit('runner');
console.log('Eu já assisti, e é muuuito legal!!!');
De acordo com o código acima, a aplicação vai registrar um novo evento chamado runner
, e em seguida vai mostrar a mensagem "Eu sempre quis te fazer uma pergunta...", depois ela vai emitir o evento runner
, que por sua vez vai perguntar ao usuário sobre o filme do blade runner, para depois mostrar a mensagem final dizendo que o filme é muito legal.
A primeira vista parece um exemplo bem bobo e sem nenhuma aplicabilidade, mas se você for parar para pensar, você pode definir seus eventos globalmente para serem ativados em partes internas do seu código, facilitando a comunicação entre elas.
Principalmente quando temos funções assíncronas, que precisamos chamar determinada parte do código mais tarde.
Métodos do event emitter
Além dos métodos on
e emit
que acabamos de conhecer acima, a classe ainda conta com algumas particularidades, vejamos:
on(eventName, listener)
: é o método usado para registrar um ouvinte. Nós já vimos ele em ação logo acima, mas eu resolvi trazer ele novamente para te mostrar que é possível não só registrar um evento, como também receber argumentos dentro desse evento.
eventEmitter.on('eventoPersonalizado', (arg1, arg2) => {
console.log(`Evento Personalizado foi acionado com argumentos ${arg1} e ${arg2}`);
});
emit(eventName, [args])
: é o método usado para emitir um evento específico. Também já fizemos o uso dele, mas para dar contexto ao que fizemos anteriormente, também podemos passar alguns argumentos junto a ele.
eventEmitter.emit('eventoPersonalizado', 'Portal', 'Micilini');
removeListener(eventName, listener)
: é o método usado para remover um determinado ouvinte.
const meuOuvinte = (arg1, arg2) => {
console.log(`Evento Personalizado foi acionado com argumentos ${arg1} e ${arg2}`);
};
eventEmitter.on('eventoPersonalizado', meuOuvinte);
// Removendo o ouvinte
eventEmitter.removeListener('eventoPersonalizado', meuOuvinte);
Observe no código acima, que o ouvinte foi definido dentro de uma variável específica, e não diretamente dentro do método como vinhamos fazendo antes.
once(eventName, listener)
: é o método usado para registrar um ouvinte de modo que ele seja acionado apenas uma única vez.
eventEmitter.once('eventoOnce', () => {
console.log('Este ouvinte será acionado apenas uma vez.');
});
eventEmitter.emit('eventoOnce');//Resultado: 'Este ouvinte será acionado apenas uma vez.'
eventEmitter.emit('eventoOnce');//Nada vai acontecer...
Para saber com mais riqueza de detalhes como funciona o módulo events
, não deixe de consultar a documentação.
Módulo fs (File System)
Um dos módulos bastante utilizados pelos desenvolvedores NodeJS é o fs (File System)
, ele é considerado um dos módulos principais que nos dá a possibilidade de se trabalhar com a criação de diretórios e arquivos.
Uma coisa que o Javascript (Client Side) foi incapaz de fazer (por questões de segurança).
Vamos começar criando o nosso arquivo app.js
na pasta do seu projeto, e após isso fazer a implementação do nosso módulo fs
:
/* Aplicação de Testes (app.js) */
const fs = require('fs');
Agora vamos aprender um pouco mais sobre os seus métodos 😉
Métodos do fs (file system)
fs.readFile()
: é um método usado para ler um determinado arquivo que esta salvo localmente de forma assíncrona.
fs.readFile('meu-arquivo.txt', 'utf8', (err, data) => {
if (err) {
console.error('Ocorreu um erro durante a abertura do arquivo: ' + err);
return;
}
console.log('Conteúdo do Arquivo: ' + data);
});
Como podemos ver, estamos executando um comando responsável por abrir um arquivo chamado 'meu-arquivo.txt'
, que existe na mesma pasta do nosso projeto.
Observação: Caso esse arquivo existisse dentro de uma pasta específica, você deverá informar o caminho dentro do primeiro parâmetro, exemplo: 'minha/pasta/meu-arquivo.txt'
.
O segundo parâmetro 'utf8'
, refere-se ao charset que será usado durante a abertura do arquivo (de modo a evitar caracteres estranhos, oferecendo compatibilidade).
Já o terceiro parâmetro, refere-se a função de callback
, que por sua vez retorna dois parâmetros:
err
: representa algum tipo de erro caso o arquivo não consiga abrir.
data
: representa o conteúdo existente dentro desse arquivo.
Como faço para ler um arquivo JSON usando o fs.readfile()?
Para abrir um arquivo JSON, basta executar a mesma lógica acima, adicionando outras funções do próprio Javascript como o JSON.PARSE
por exemplo.
const fs = require('fs');
const nomeArquivo = 'dados.json';
fs.readFile(nomeArquivo, 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
try {
const arrayDeDados = JSON.parse(data);
console.log('Array obtido do arquivo JSON:', arrayDeDados);
} catch (error) {
console.error('Erro ao analisar o JSON:', error);
}
});
É importante ressaltar que o método fs.readfile()
é assíncrono, e isso significa dizer que a sua aplicação continua rodando normalmente enquanto o arquivo ainda está sendo carregado.
Caso você precisa travar a aplicação enquanto o arquivo é aberto, você pode fazer o uso do método abaixo.
fs.readFileSync()
: é um método síncrono que bloqueia a execução da sua aplicação até que a leitura do arquivo seja concluída.
try {
const conteudo = fs.readFileSync('meu-arquivo.txt', 'utf8');
console.log('Conteúdo do arquivo:', conteudo);
} catch (error) {
console.error('Erro ao ler o arquivo:', error);
}
Observe que esse método não possui uma função de callback
, pois ele é síncrono.
Observe também, que abaixo temos um outro exemplo de como abrir e interpretar um arquivo JSON:
try {
const conteudoJSON = fs.readFileSync('dados.json', 'utf8');
const objetoDeDados = JSON.parse(conteudoJSON);
console.log('Objeto obtido do arquivo JSON:', objetoDeDados);
} catch (error) {
console.error('Erro ao ler o arquivo JSON:', error);
}
É importante ressaltar que os métodos readFile
e readFileSync
, também podem abrir outros tipos de arquivos como imagens, vídeos e afins.
fs.writeFile()
: é um método usado para salvar um novo arquivo, ou sobreescrever o conteúdo de um arquivo existente de forma assíncrona. (Esse método não cria diretórios)
fs.writeFile('novo-arquivo.txt', 'Conteúdo que será salvo dentro do arquivo', 'utf8', (err) => {
if (err) {
console.error('Ocorreu um erro na escrita: ' + err);
return;
}
console.log('Arquivo foi escrito com sucesso.');
});
Observe que o segundo parâmetro é o conteúdo que será salvo dentro desse arquivo. Note que esse método é assíncrono, e não trava a execução do seu programa enquanto salva o arquivo.
fs.writeFileSync()
: é um método usado para salvar um novo arquivo , ou quem sabe, sobreescrever o conteúdo de um arquivo existente de forma síncrona.(Esse método não cria diretórios)
try {
const dadosParaEscrever = 'Este é um exemplo de conteúdo para o arquivo.';
fs.writeFileSync('novo-arquivo.txt', dadosParaEscrever, 'utf8');
console.log('Conteúdo foi escrito no arquivo com sucesso.');
} catch (error) {
console.error('Erro ao escrever no arquivo:', error);
}
fs.mkdir()
: é um método usado para criar pastas (diretórios).
fs.mkdir('minha-pasta', (err) => {
if (err) {
console.error('Erro ao criar um diretório: ' + err);
return;
}
console.log('Diretório criado com sucesso.');
});
fs.readdir()
: é um método usado para ler e retornar o conteúdo existente em um diretório.
fs.readdir('.', (err, files) => {
if (err) {
console.error('Erro ao ler diretório' + err);
return;
}
console.log('Arquivos no diretório atual:', files);
});
Observe que o primeiro parâmetro é o caminho do diretório que será lido, nesse caso, estamos lendo a pasta atual do projeto, mas poderia ser 'minha-pasta'
ou 'minha-pasta/icones/'
por exemplo.
fs.unlink()
: é um método usado para apagar um determinado arquivo.
fs.unlink('meu-arquivo.txt', (err) => {
if (err) {
console.error('Erro durante a remoção do arquivo: ' + err);
return;
}
console.log('Arquivo removido com sucesso.');
});
fs.rmdir()
: é um método usado para apagar um determinado diretório.
const diretorio = 'minha-pasta';
fs.rmdir(diretorio, {
recursive: true
}, (err) => {
if (err) {
console.error('Erro ao remover o diretório:', err);
} else {
console.log('Diretório removido com sucesso.');
}
});
Observe que o segundo parâmetro diz se a remoção será recursiva (true
) ou não (false
). Caso o parâmetro estiver setado como true, ele irá remover o diretório e todos os seus conteúdos de forma recursiva.
fs.rename()
: é um método usado para renomear arquivo e diretórios.
fs.rename('novo-arquivo.txt', 'novo-novo-arquivo.txt', (err) => {
if (err) {
console.error('Erro durante o processo: ' + err);
return;
}
console.log('Arquivo renomeado com sucesso.');
});
fs.stat()
: é um método usado para recuperar as estatísticas de um determinado arquivo.
fs.stat('novo-novo-arquivo.txt', (err, stats) => {
if (err) {
console.error('Erro durante o processo: ' + err);
return;
}
console.log('Estatísticas do arquivo: ', stats);
});
Observação: O retorno deste método, representa um objeto de elementos.
fs.copy()
: é um método usado para copiar um determinado arquivo.
fs.copyFile('origem.txt', 'destino.txt', (err) => {
if (err) {
console.error('Erro durante o processo: ' + err);
return;
}
console.log('Arquivo copiado com sucesso.');
});
fs.watch()
: é um método bastante similar ao módulo events
, onde permite que você assista ás mudanças em arquivos ou diretórios.
const watcher = fs.watch('novo-novo-arquivo.txt');
watcher.on('change', (event, filename) => {
console.log(`O arquivo ${filename} foi alterado.`);
});
fs.existsSync()
: é um método usado para verificar se um arquivo ou diretório existe de forma síncrona.
const caminhoArquivo = 'caminho/do/seu/arquivo.txt';
const caminhoDiretorio = 'caminho/do/seu/diretorio';
// Verificando a existência de um arquivo de forma síncrona
if (fs.existsSync(caminhoArquivo)) {
console.log('O arquivo existe.');
} else {
console.log('O arquivo não existe.');
}
// Verificando a existência de um diretório de forma síncrona
if (fs.existsSync(caminhoDiretorio)) {
console.log('O diretório existe.');
} else {
console.log('O diretório não existe.');
}
fs.promises.access()
: é um método usado para verificar se um arquivo ou diretório existe de forma assíncrona.
const caminhoArquivo2 = 'caminho/do/seu/arquivo.txt';
const caminhoDiretorio2 = 'caminho/do/seu/diretorio';
// Verificando a existência de um arquivo de forma assíncrona
fs.access(caminhoArquivo2)
.then(() => {
console.log('O arquivo existe.');
})
.catch((err) => {
console.log('O arquivo não existe.');
});
// Verificando a existência de um diretório de forma assíncrona
fs.access(caminhoDiretorio2)
.then(() => {
console.log('O diretório existe.');
})
.catch((err) => {
console.log('O diretório não existe.');
});
Criando arquivos e diretórios de forma automática
Caso você queria criar arquivos existentes em diretórios de forma automática, você pode fazer isso em conjunto com os módulos path
e fs
da seguinte forma:
const fs = require('fs');
const path = require('path');
const diretorio = 'caminho/do/seu/diretorio';
const nomeArquivo = 'arquivo.txt';
const caminhoCompleto = path.join(diretorio, nomeArquivo);
// Garantindo a existência do diretório
if (!fs.existsSync(diretorio)) {
fs.mkdirSync(diretorio, { recursive: true });
}
// Escrevendo no arquivo
const novosDados = 'Estes são os novos dados para o arquivo.';
fs.writeFileSync(caminhoCompleto, novosDados, 'utf8');
console.log('Arquivo atualizado com sucesso.');
Para saber mais sobre o funcionamento do módulo fs
, não deixe de consultar a documentação.
Módulo url
Como o próprio nome já nos diz, o módulo url
nos oferece uma série de de funções para trabalhar com URLs (Uniform Resource Locators
).
Ele permite que você faça validações, formatações e manipulações de strings que representam URLs.
Para começarmos, crie um novo arquivo chamado app.js
dentro da pasta do seu projeto, e comece importando o módulo url
:
/* Aplicação de Testes (app.js) */
const url = require('url');
Feito isso, partiu colocar a mão na massa 😉
Métodos do url
url.parse(urlString, [parseQueryString], [slashesDenoteHost])
: é um método que analisa uma URL, e retorna um objeto com suas partes componentes.
const minhaURL = 'https://www.micilini.com/path?query=123#fragmento';
const parsedUrl = url.parse(minhaURL, true);
console.log(parsedUrl);
url.format(urlObject)
: é um método que gera uma URL formatada a partir de um objeto de URL.
const minhaURLCustomizada = {
protocol: 'https:',
host: 'www.micilini.com',
pathname: '/path',
query: { query: '123' },
hash: 'fragmento'
};
const formattedUrl = url.format(minhaURLCustomizada);
console.log(formattedUrl);
url.resolve(from, to)
: é um método que resolve uma URL alternativa em relação a outra URL.
const baseUrl = 'https://www.micilini.com/path/';
const relativeUrl = '../cursos.html';
const resolvedUrl = url.resolve(baseUrl, relativeUrl);
console.log(resolvedUrl);
url.resolveObject(from, to)
: é um método que funciona similar ao resolve()
, mas que retorna um objeto de URL.
//resolveObject
const baseUrl2 = 'https://www.micilini.com/path/';
const relativeUrl2 = '../curso.html';
const resolvedUrlObject2 = url.resolveObject(baseUrl2, relativeUrl2);
console.log(resolvedUrlObject2);
Como verificar se uma URL é válida ou não?
Para isso, você precisa instanciar a classe do módulo URL dentro de uma estrutura de try..catch
da seguinte forma:
function isValidURL(url) {
try {
// Tenta analisar a URL
const parsedUrl = new URL(url);
return true;
} catch (error) {
// Se ocorrer um erro, a URL não é válida
return false;
}
}
// Exemplo de uso:
const urlToCheck = 'https://www.micilini.com';
if (isValidURL(urlToCheck)) {
console.log('A URL é válida.');
} else {
console.log('A URL não é válida.');
}
Para mais informações sobre o módulo url
, não deixe de consultar a documentação.
Módulo os
Um dos módulos mais interessantes já criados pela equipe de desenvolvimento do NodeJS é o os
, ele é capaz de extrair informações variadas do sistema operacional onde a aplicação está rodando.
Para utiliza-lo, comece criando o arquivo app.js
dentro da pasta do seu projeto, e em seguida basta importar o módulo os
da seguinte forma:
/* Aplicação de Testes (app.js) */
const os = require('os');
Feito isso, vamois testar alguns de seus métodos.
Métodos do os
os.platform()
: é um método que retorna a plataforma do sistema operacional (win32, linux, darwin)
console.log('Plataforma Atual:', os.platform()); // Exibe a plataforma do sistema (ex: win32, linux, darwin)
os.arch()
: é um método que retorna a arquitetura do processador.
console.log('Arquitetura:', os.arch()); // Exibe a arquitetura do processador (ex: x64, arm64)
os.totalmem()
: é um método capaz de retornar a quantidade de memoria RAM instalada na máquina.
console.log('Memória total (bytes):', os.totalmem()); // Retorna a quantidade total de memória do sistema
os.freemem()
: é um método capaz de retornar a quantidade de memória livre na máquina.
console.log('Memória livre (bytes):', os.freemem()); // Retorna a quantidade de memória livre no sistema
os.cpus()
: é um método que retorna as informações relacionadas a CPU.
console.log('Informações da CPU:', os.cpus()); // Retorna um array com informações sobre os núcleos da CPU
os.userInfo()
: é um método que retorna informações relacionadas ao usuário atual (uid
, gid
, username
, homedir
, e shell
).
console.log('Usuário atual:', os.userInfo()); // Retorna informações sobre o usuário atual
os.tmpdir()
: é um método que retorna o diretório temporário do sistema atual.
console.log('Diretório temporário:', os.tmpdir()); // Retorna o diretório temporário do sistema
Para mais informações sobre o funcionamento do módulo os
, não deixe de consultar a documentação.
Conclusão
Ufa 😅
Nesta lição aprendemos bastante coisa sobre alguns dos módulos principais do NodeJS.
Não chegamos a ver toooodos os métodos de cada um dos módulos, até porque são milhares deles, e a documentação está aí pra isso 😄 (E eu ficaria horas e horas falando sobre eles).
Na próxima lição, entraremos de cabeça em um dos módulos mais utilizados, o famoso módulo http
, responsável por dar a vida em algumas (se não a maioria) das aplicações web.
Te encontro lá 😉