Node.js: Sistema de Arquivos

Última atualização: 2026-08-26

Charlie é um engenheiro de back-end responsável pela manutenção da plataforma de análise de logs da empresa. Todos os dias, ao amanhecer, o sistema precisa processar aproximadamente 50.000 linhas de arquivos de log do servidor. Inicialmente, ele usava o fs.readFileSync para ler os logs um por um, mas o programa inteiro travava completamente durante o processo de leitura, fazendo com que todas as outras solicitações atingissem o tempo limite. Depois de mudar para a leitura assíncrona com fs.readFile, o programa passou a ser capaz de responder a outras solicitações enquanto aguardava a E/S do disco, resultando em um aumento de 10 vezes na taxa de transferência geral. Essa experiência proporcionou a ele uma compreensão profunda da diferença entre operações síncronas e assíncronas na API do sistema de arquivos do Node.js.

1. O que você vai aprender



2. Visão geral do módulo fs

O módulo fs é um módulo integrado do Node.js para operações no sistema de arquivos, oferecendo recursos como leitura e gravação de arquivos, gerenciamento de diretórios e verificações de permissões. Cada operação geralmente oferece três estilos: síncrona, assíncrona com callback e assíncrona com Promise.

Recurso Método síncrono Método de callback assíncrono Método fs.promises
Característica de nomenclatura xxxSync Sufixo Sem sufixo fs.promises.xxx
Valor de retorno Retorna o resultado diretamente undefined, obtido por meio de um callback Retorna Promise
Bloqueia o ciclo de eventos Sim Não Não
Tratamento de erros try/catch Primeiro parâmetro da função de retorno de chamada .catch() / try-catch
Casos de uso recomendados Carregar a configuração na inicialização Compatibilidade com versões anteriores A melhor opção para novos projetos
JAVASCRIPT
const fs = require('fs');

// Synchronize
const data = fs.readFileSync('config.json', 'utf8');

// Asynchronous Callbacks
fs.readFile('config.json', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);
});

// Promise
const fsPromises = require('fs/promises');
fsPromises.readFile('config.json', 'utf8')
  .then(data => console.log(data))
  .catch(err => console.error(err));


3. Sequências de execução síncronas versus assíncronas

Os métodos síncronos bloqueiam o ciclo de eventos e não continuam a executar o código subsequente até que a operação com o arquivo esteja concluída. Os métodos assíncronos, por outro lado, retornam imediatamente e notificam o resultado por meio de um callback ou de uma Promise assim que a operação com o arquivo estiver concluída.

100%
sequenceDiagram
    participant Main as Main Thread
    participant FS_Sync as Synchronous Read
    participant FS_Async as Asynchronous Reading
    participant Disk as Disk I/O

    Note over Main,Disk: Synchronous Execution Process
    Main->>FS_Sync: readFileSync('log.txt')
    FS_Sync->>Disk: Read a File(Blocking Wait)
    Disk-->>FS_Sync: Return Data
    FS_Sync-->>Main: Continue executing the following code
    Note right of Main: All other requests are on hold

    Note over Main,Disk: Asynchronous Execution Flow
    Main->>FS_Async: readFile('log.txt', callback)
    FS_Async->>Disk: Submit a read request
    FS_Async-->>Main: Return Now,Continue Execution
    Note right of Main: Can handle other requests
    Disk-->>FS_Async: I/O Done
    FS_Async-->>Main: Execute the callback function

▶ Exemplo: A leitura síncrona bloqueia todo o programa

JAVASCRIPT
const fs = require('fs');

console.log('Start Reading...');
const data = fs.readFileSync('big-log.txt', 'utf8');
console.log('Reading complete,Number of lines:', data.split('\n').length);
console.log('This line must wait until the data has finished loading before it is executed.');
▶ Experimente
TEXT 📖 Somente leitura
Start Reading...
Reading complete,Number of lines:50000
This line must wait until the data has finished loading before it is executed.

▶ Exemplo: Leitura assíncrona sem bloquear o ciclo de eventos

JAVASCRIPT
const fs = require('fs');

console.log('Start Reading...');
fs.readFile('big-log.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log('Reading complete,Number of lines:', data.split('\n').length);
});
console.log('This line is executed immediately,No need to wait for the data to be read');
▶ Experimente
TEXT 📖 Somente leitura
Start Reading...
This line is executed immediately,No need to wait for the data to be read
Reading complete,Number of lines:50000


4. Operações de leitura e gravação em arquivos

Método Parâmetros Finalidade
fs.readFile(path, encoding, callback) Caminho, codificação, callback Leitura assíncrona de todo o arquivo
fs.readFileSync(path, encoding) Caminho, codificação Ler o arquivo inteiro de forma síncrona
fs.writeFile(path, data, encoding, callback) Caminho, Dados, Codificação, Callback Gravação assíncrona (sobrescrita)
fs.writeFileSync(path, data, encoding) Caminho, Dados, Codificação Gravação em sincronia (sobrescrita)
fs.appendFile(path, data, encoding, callback) Caminho, Dados, Codificação, Callback Acrescentamento assíncrono
fs.appendFileSync(path, data, encoding) Caminho, Dados, Codificação Sincronizar conteúdo anexado
fs.unlink(path, callback) Caminho, Callback Exclusão assíncrona de arquivos
fs.unlinkSync(path) Caminho Excluir arquivos simultaneamente

▶ Exemplo: Gravação e adição de dados a arquivos

JAVASCRIPT
const fs = require('fs');

fs.writeFile('output.txt', 'Content on the first line\n', 'utf8', (err) => {
  if (err) throw err;
  console.log('Write complete');

  fs.appendFile('output.txt', 'The second line added\n', 'utf8', (err) => {
    if (err) throw err;
    console.log('Addition Complete');

    fs.readFile('output.txt', 'utf8', (err, data) => {
      if (err) throw err;
      console.log('Document Content:\n', data);
    });
  });
});
▶ Experimente
TEXT 📖 Somente leitura
Write complete
Addition Complete
Document Content:
 Content on the first line
The second line added

▶ Exemplo: Usando fs.promises para evitar callbacks aninhados

JAVASCRIPT
const fs = require('fs/promises');

async function writeAndRead() {
  try {
    await fs.writeFile('output.txt', 'Content on the first line\n', 'utf8');
    console.log('Write complete');
    await fs.appendFile('output.txt', 'The second line added\n', 'utf8');
    console.log('Addition Complete');
    const data = await fs.readFile('output.txt', 'utf8');
    console.log('Document Content:\n', data);
  } catch (err) {
    console.error('Operation Failed:', err.message);
  }
}

writeAndRead();
▶ Experimente

▶ Exemplo: Exclusão de um arquivo

JAVASCRIPT
const fs = require('fs/promises');

async function deleteFile() {
  try {
    await fs.unlink('output.txt');
    console.log('The file has been deleted');
  } catch (err) {
    console.error('Deletion Failed:', err.message);
  }
}

deleteFile();
▶ Experimente

5. Operações com diretórios

Método Parâmetros Finalidade
fs.mkdir(path, options, callback) Caminho, {recursive}, Callback Criar diretório
fs.readdir(path, options, callback) Caminho, {withFileTypes}, Callback Listar o conteúdo do diretório
fs.stat(path, callback) Caminho, Callback Obter informações sobre arquivos/diretórios
fs.existsSync(path) Caminho Verificar se o caminho existe

▶ Exemplo: Criando um diretório e listando seu conteúdo

JAVASCRIPT
const fs = require('fs/promises');

async function dirOperations() {
  try {
    await fs.mkdir('logs', { recursive: true });
    console.log('The directory was successfully created');

    await fs.writeFile('logs/app.log', '2025-01-01 Server started\n', 'utf8');
    await fs.writeFile('logs/error.log', '2025-01-01 Connection timeout\n', 'utf8');

    const files = await fs.readdir('logs');
    console.log('Table of Contents:', files);
  } catch (err) {
    console.error('Operation Failed:', err.message);
  }
}

dirOperations();
▶ Experimente
TEXT 📖 Somente leitura
The directory was successfully created
Table of Contents: [ 'app.log', 'error.log' ]

▶ Exemplo: Como determinar se é um arquivo ou um diretório

JAVASCRIPT
const fs = require('fs/promises');

async function checkType() {
  const stats = await fs.stat('logs');
  console.log('logs This is the table of contents:', stats.isDirectory());
  console.log('logs It is a file:', stats.isFile());

  const fileStats = await fs.stat('logs/app.log');
  console.log('app.log It is a file:', fileStats.isFile());
  console.log('File size:', fileStats.size, 'bytes');
}

checkType();
▶ Experimente
TEXT 📖 Somente leitura
logs This is the table of contents: true
logs It is a file: false
app.log It is a file: true
File size: 29 bytes


6. Comparação entre callbacks do tipo “error-first” e promessas

A API do sistema de arquivos do Node.js segue a convenção de “callback com erro em primeiro lugar”: o primeiro argumento da função de callback é sempre um objeto de erro; se não houver erro, é null. fs.promises utiliza o mecanismo padrão de Promise para lidar com erros.

Item de comparação Callback “Error-First” fs.promises
Assinatura da função (err, data) => {} Retorna Promise<data>
Erro de julgamento if (err) Verificar try/catch ou .catch()
Problemas de aninhamento Propenso ao “callback hell” async/await Simplificação
Cenários típicos Compatibilidade com projetos legados Recomendações para novos projetos
Método de importação require('fs') require('fs/promises')

▶ Exemplo: Uma comparação entre dois métodos de tratamento de erros

JAVASCRIPT
const fsCallback = require('fs');
const fsPromise = require('fs/promises');

// Error-First Callback
fsCallback.readFile('not-exist.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Callback Method - Error:', err.code);
    return;
  }
  console.log(data);
});

// Promise Method
async function readWithPromise() {
  try {
    const data = await fsPromise.readFile('not-exist.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error('PromiseMethod - Error:', err.code);
  }
}

readWithPromise();
▶ Experimente
TEXT 📖 Somente leitura
Callback Method - Error: ENOENT
PromiseMethod - Error: ENOENT


7. Codificação de arquivos

Código Descrição Cenários aplicáveis Exemplo
'utf8' Codificação de texto UTF-8 (padrão) Leitura e gravação de arquivos de texto Logs, configurações, JSON
'base64' Codificação Base64 Transferência de imagens, conversão de binário para texto Imagens incorporadas, anexos de e-mail
'binary' ('latin1') Bytes brutos Operações de baixo nível com arquivos binários Processamento de imagens e arquivos compactados
null Retornar ao objeto buffer É necessário manipular bytes brutos Verificação de arquivos, processamento de fluxos

▶ Exemplo: Lendo o mesmo arquivo com diferentes codificações

JAVASCRIPT
const fs = require('fs/promises');

async function readEncodings() {
  await fs.writeFile('sample.txt', 'Hello The World', 'utf8');

  const utf8Data = await fs.readFile('sample.txt', 'utf8');
  console.log('UTF-8:', utf8Data);

  const base64Data = await fs.readFile('sample.txt', 'base64');
  console.log('Base64:', base64Data);

  const bufferData = await fs.readFile('sample.txt');
  console.log('Buffer:', bufferData);
  console.log('Buffer Hexadecimal:', bufferData.toString('hex'));
}

readEncodings();
▶ Experimente
TEXT 📖 Somente leitura
UTF-8: Hello The World
Base64: SGVsbG8g5LiW55WM
Buffer: <Buffer 48 65 6c 6c 6f 20 e4 b8 96 e7 95 8c>
Buffer Hexadecimal: 48656c6c6f20e4b896e7958c


8. Exemplo abrangente: Ferramenta de gerenciamento de arquivos

Crie um fluxo de trabalho completo para gerenciamento de arquivos: Criar um diretório → Escrever a configuração → Ler e analisar → Adicionar ao log → Listar o conteúdo.

JAVASCRIPT
const fs = require('fs/promises');
const path = require('path');

async function fileManager() {
  const dir = 'project-data';
  const configPath = path.join(dir, 'config.json');
  const logPath = path.join(dir, 'app.log');

  try {
    // Step 1: Create a Directory
    await fs.mkdir(dir, { recursive: true });
    console.log('✓ The table of contents has been created:', dir);

    // Step 2: Write to the configuration file
    const config = {
      appName: 'LogAnalyzer',
      version: '1.0.0',
      maxLines: 50000,
      encoding: 'utf8'
    };
    await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');
    console.log('✓ The configuration file has been written.:', configPath);

    // Step 3: Read and Parse the Configuration
    const raw = await fs.readFile(configPath, 'utf8');
    const parsed = JSON.parse(raw);
    console.log('✓ Configuration loaded:', parsed.appName, 'v' + parsed.version);

    // Step 4: Add a log entry
    const timestamp = new Date().toISOString();
    await fs.appendFile(logPath, `[${timestamp}] Service started\n`, 'utf8');
    await fs.appendFile(logPath, `[${timestamp}] Config loaded: ${parsed.maxLines} lines\n`, 'utf8');
    console.log('✓ The log has been appended.:', logPath);

    // Step 5: List the contents of the table of contents
    const entries = await fs.readdir(dir, { withFileTypes: true });
    console.log('✓ Table of Contents:');
    for (const entry of entries) {
      const type = entry.isDirectory() ? '[DIR]' : '[FILE]';
      const stats = await fs.stat(path.join(dir, entry.name));
      console.log(`  ${type} ${entry.name} (${stats.size} bytes)`);
    }
  } catch (err) {
    console.error('✗ Operation Failed:', err.message);
  }
}

fileManager();
TEXT 📖 Somente leitura
✓ The table of contents has been created: project-data
✓ The configuration file has been written.: project-data/config.json
✓ Configuration loaded: LogAnalyzer v1.0.0
✓ The log has been appended.: project-data/app.log
✓ Table of Contents:
  [FILE] app.log (106 bytes)
  [FILE] config.json (98 bytes)

❓ Perguntas Frequentes

P: Quando os métodos síncronos devem ser usados? R: Use-os apenas para operações únicas, como carregar arquivos de configuração, durante a inicialização do aplicativo. Nunca use métodos síncronos em tempo de execução, pois eles bloquearão o ciclo de eventos.

P: Por que o primeiro parâmetro da função de retorno de chamada é err? R: Essa é a convenção de “função de retorno de chamada com erros em primeiro lugar” do Node.js, que exige que os desenvolvedores verifiquem se há erros antes de processar os dados, evitando assim que exceções sejam ignoradas.

P: Qual é a diferença entre fs.promises e fs? R: fs.promises (ou require('fs/promises')) oferece a mesma funcionalidade, mas retorna uma Promise; async/await pode ser usado como alternativa às chamadas de retorno aninhadas; fs usa o estilo de callback — ambos são funcionalmente idênticos.

P: Como posso determinar se um caminho é um arquivo ou um diretório? R: Use fs.stat(path) para obter o objeto stats; em seguida, chame stats.isFile() para verificar se é um arquivo e stats.isDirectory() para verificar se é um diretório.

P: O readFile carrega o arquivo inteiro na memória? R: Sim, o readFile lê o arquivo inteiro na memória. Ao trabalhar com arquivos grandes, você deve usar o fs.createReadStream para lê-los em fluxos, a fim de evitar um estouro de memória.

P: Qual é a finalidade da opção recursive em fs.mkdir? R: Ao definir { recursive: true }, é possível criar vários níveis de diretórios aninhados de uma só vez, de forma semelhante a mkdir -p, e o sistema não exibirá um erro mesmo que o diretório já exista.


📖 Resumo


📝 Exercícios

  1. Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
  2. Modifique o exemplo completo e adicione suas próprias extensões
  3. Analise a documentação oficial, identifique 1 ou 2 APIs que não foram abordadas nesta aula e escreva um código de teste para elas.
  4. Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
  5. Tente combinar o que você aprendeu nesta aula com o conteúdo das aulas anteriores para criar um pequeno projeto.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%