Introdução: por que trabalhar com arquivos em JavaScript é essencial
\n\nImagine que você é o capitão de uma nave espacial. Sua tarefa é gerenciar os compartimentos de carga, os suprimentos de oxigênio e o diário de bordo. No mundo do desenvolvimento web, o sistema de arquivos são esses compartimentos, e o JavaScript é o seu painel de controle. Sem a habilidade de trabalhar com arquivos, você ficará preso em órbita: não conseguirá salvar as configurações do usuário, carregar a configuração do servidor ou processar arquivos de log.
\n\nMuitos iniciantes pensam que o JavaScript vive apenas no navegador e não consegue tocar em arquivos no disco. Isso é um mito! Com o surgimento do Node.js (e até mesmo em navegadores modernos através da File API), o JavaScript se tornou uma ferramenta completa para trabalhar com o sistema de arquivos. Hoje, vamos abordar como ler, escrever, excluir e mover arquivos, além de como não cair na armadilha da assincronicidade.
\n\nA propósito, se você está apenas começando sua jornada na programação, recomendo primeiro estudar os fundamentos do JavaScript — isso ajudará a entender mais rapidamente os exemplos abaixo.
\n\nOnde o JavaScript trabalha com arquivos? Dois mundos — duas abordagens
\n\nAntes de mergulharmos no código, vamos esclarecer: as operações com arquivos em JS se dividem em dois campos.
\n\n1. JavaScript no servidor (Node.js)
\nAqui temos acesso total ao sistema de arquivos: criação, exclusão, renomeação, leitura de fluxos — tudo o que você desejar. Trabalhamos através do módulo embutido fs (File System). É como um canivete suíço para trabalhar com arquivos.
2. JavaScript no cliente (navegador)
\nO navegador é uma "sandbox" com restrições. Você não pode simplesmente pegar e ler qualquer arquivo do computador do usuário (senão os hackers estariam comemorando). Mas é possível trabalhar com arquivos que o próprio usuário selecionou através de <input type="file">, ou através da API FileReader e Blob.
Neste artigo, vamos nos concentrar no Node.js, mas no final daremos um bônus — um exemplo para o navegador.
\n\nMódulo fs: sua principal ferramenta
\n\nNo Node.js, o trabalho com arquivos começa com a importação do módulo fs:
const fs = require('fs'); // estilo antigo\n// ou\nimport fs from 'fs'; // se estiver usando módulos ES\n\nO fs tem três modos de operação: síncrono, assíncrono com callbacks e assíncrono com promises. Usaremos o último — com async/await, pois é uma abordagem moderna e legível.
Leitura de arquivo: do simples ao complexo
\n\nSuponha que temos um arquivo data.txt com texto. A maneira mais simples de lê-lo:
import { readFile } from 'fs/promises';\n\nasync function readMyFile() {\n try {\n const data = await readFile('data.txt', 'utf-8');\n console.log(data);\n } catch (err) {\n console.error('Erro de leitura:', err.message);\n }\n}\n\nreadMyFile();\n\nO que é importante aqui? 'utf-8' — a codificação. Se não for especificada, você receberá um buffer bruto (Buffer) que precisará ser convertido em string. Para arquivos de texto, sempre especifique a codificação.
Se o arquivo for grande (por exemplo, um arquivo de log de 500 MB), lê-lo por completo é uma má ideia. É aí que os fluxos (streams) vêm em socorro:
\n\nimport { createReadStream } from 'fs';\nimport { createInterface } from 'readline';\n\nasync function readLargeFile() {\n const stream = createReadStream('bigfile.log', 'utf-8');\n const rl = createInterface({ input: stream });\n\n for await (const line of rl) {\n console.log('Linha:', line);\n // Processa cada linha à medida que é lida\n }\n}\n\nreadLargeFile();\n\nEscrita em arquivo: criando e adicionando
\n\nA escrita pode ser de dois tipos: sobrescrita (write) e adição (append). A diferença é óbvia: write apagará o arquivo antigo, append adicionará ao final.
import { writeFile, appendFile } from 'fs/promises';\n\n//