Escrita de Arquivos em Node.js Explicada: Tudo o que Você Precisa Saber Sobre fs.writeFileSync()

Operações com arquivos são uma parte fundamental de muitas aplicações Node.js. Seja criando arquivos de configuração, registrando dados ou gerando relatórios, entender como escrever arquivos de forma eficiente é essencial. O método fs.writeFileSync()
oferece uma maneira direta de lidar com operações de escrita síncrona de arquivos no Node.js.
Este guia abrangente cobre tudo o que você precisa saber sobre o uso eficaz de fs.writeFileSync()
, desde o uso básico até técnicas avançadas e melhores práticas.
Principais Pontos
fs.writeFileSync()
escreve dados em arquivos de forma síncrona, bloqueando o loop de eventos até a conclusão- Sempre use blocos try-catch para lidar com possíveis erros
- Use flags apropriadas para controlar o comportamento de criação e escrita de arquivos
- Considere as implicações de desempenho em aplicações com alta concorrência
- Para arquivos maiores ou ambientes de produção, considere alternativas assíncronas
- Esteja atento a questões de segurança, especialmente com caminhos fornecidos pelo usuário
O que é fs.writeFileSync()?
fs.writeFileSync()
é um método integrado no módulo de sistema de arquivos (fs
) do Node.js que escreve dados em um arquivo de forma síncrona. Diferentemente de sua contraparte assíncrona, este método bloqueia a execução do seu código até que a operação de arquivo seja concluída.
A assinatura do método é:
fs.writeFileSync(file, data[, options])
- file: Caminho para o arquivo (string, Buffer, URL ou descritor de arquivo)
- data: Conteúdo a ser escrito (string, Buffer, TypedArray ou DataView)
- options: Parâmetros de configuração opcionais (string ou objeto)
Uso Básico de fs.writeFileSync()
Escrevendo um Arquivo de Texto Simples
const fs = require('fs');
try {
fs.writeFileSync('example.txt', 'Hello, Node.js!');
console.log('Arquivo escrito com sucesso');
} catch (err) {
console.error('Erro ao escrever arquivo:', err);
}
Este código cria um arquivo chamado example.txt
com o conteúdo ""Hello, Node.js!"" no seu diretório de trabalho atual.
Escrevendo Dados JSON
const fs = require('fs');
const user = {
name: 'John Doe',
age: 30,
email: 'john@example.com'
};
try {
fs.writeFileSync('user.json', JSON.stringify(user, null, 2));
console.log('Arquivo JSON escrito com sucesso');
} catch (err) {
console.error('Erro ao escrever arquivo JSON:', err);
}
Entendendo os Parâmetros
O Parâmetro File
O primeiro parâmetro especifica o caminho do arquivo onde os dados serão escritos:
// Escrevendo no diretório atual
fs.writeFileSync('data.txt', 'Algum conteúdo');
// Escrevendo em um caminho específico
fs.writeFileSync('/var/logs/app.log', 'Entrada de log');
// Usando um descritor de arquivo
const fd = fs.openSync('config.json', 'w');
fs.writeFileSync(fd, '{""setting"": ""value""}');
fs.closeSync(fd);
Importante: Se o diretório especificado não existir, o Node.js lançará um erro. O método fs.writeFileSync()
não pode criar diretórios.
O Parâmetro Data
O segundo parâmetro contém o conteúdo que você deseja escrever:
// Escrevendo uma string
fs.writeFileSync('file.txt', 'Conteúdo de texto simples');
// Escrevendo um Buffer
const buffer = Buffer.from('Conteúdo binário');
fs.writeFileSync('binary.dat', buffer);
// Escrevendo um TypedArray
const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // ""Hello"" em ASCII
fs.writeFileSync('typed-array.txt', uint8Array);
Trabalhando com Buffers
Buffers são particularmente úteis ao lidar com dados binários:
const fs = require('fs');
// Criando um buffer a partir de uma string
const stringData = 'Hello World';
const buffer = Buffer.from(stringData, 'utf8');
fs.writeFileSync('buffer-example.txt', buffer);
// Criando um buffer a partir de JSON
const userData = { name: 'Alice', age: 28 };
const jsonBuffer = Buffer.from(JSON.stringify(userData));
fs.writeFileSync('user-data.json', jsonBuffer);
O Parâmetro Options
O terceiro parâmetro permite personalizar o comportamento de escrita do arquivo:
fs.writeFileSync('config.txt', 'Dados de configuração', {
encoding: 'utf8', // Codificação de caracteres (padrão: 'utf8')
mode: 0o666, // Permissões do arquivo (padrão: 0o666)
flag: 'w' // Flag do sistema de arquivos (padrão: 'w')
});
Opções Comuns de Flag
'w'
: Abrir para escrita, criar se não existir, truncar se existir (padrão)'a'
: Abrir para anexar, criar se não existir'wx'
: Como ‘w’, mas falha se o caminho existir'ax'
: Como ‘a’, mas falha se o caminho existir'r+'
: Abrir para leitura e escrita, o arquivo deve existir
// Anexar a um arquivo em vez de sobrescrevê-lo
fs.writeFileSync('log.txt', 'Nova entrada de logn', { flag: 'a' });
// Criar um novo arquivo apenas se ele não existir
try {
fs.writeFileSync('config.json', '{}', { flag: 'wx' });
console.log('Novo arquivo de configuração criado');
} catch (err) {
if (err.code === 'EEXIST') {
console.log('Arquivo de configuração já existe');
} else {
console.error('Erro:', err);
}
}
Tratamento de Erros com fs.writeFileSync()
Como fs.writeFileSync()
é síncrono, os erros são lançados diretamente. Sempre envolva-o em um bloco try-catch:
try {
fs.writeFileSync('/path/to/file.txt', 'Conteúdo');
} catch (error) {
// Lidar com tipos específicos de erro
if (error.code === 'ENOENT') {
console.error('Diretório não existe');
} else if (error.code === 'EACCES') {
console.error('Permissão negada');
} else {
console.error('Erro inesperado:', error);
}
}
Códigos de Erro Comuns
ENOENT
: Arquivo ou diretório não existe (frequentemente quando o diretório pai não existe)EACCES
: Permissão negadaEISDIR
: É um diretório (tentando escrever em um diretório)EMFILE
: Muitos arquivos abertosEEXIST
: Arquivo já existe (quando usando flags ‘wx’ ou ‘ax’)
Casos de Uso Práticos
Criando Arquivos de Configuração
const fs = require('fs');
function createDefaultConfig() {
const config = {
apiKey: '',
debug: false,
logLevel: 'info',
maxRetries: 3
};
try {
fs.writeFileSync('config.json', JSON.stringify(config, null, 2));
console.log('Configuração padrão criada');
} catch (err) {
console.error('Falha ao criar arquivo de configuração:', err);
}
}
// Verificar se a configuração existe, criar se não
try {
fs.accessSync('config.json', fs.constants.F_OK);
console.log('Arquivo de configuração já existe');
} catch (err) {
createDefaultConfig();
}
Logging Simples
function logMessage(message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}n`;
try {
fs.writeFileSync('app.log', logEntry, { flag: 'a' });
} catch (err) {
console.error('Falha ao escrever no arquivo de log:', err);
}
}
logMessage('Aplicação iniciada');
// Fazer algo
logMessage('Operação concluída');
Salvando Entrada do Usuário
const readline = require('readline-sync');
const fs = require('fs');
function saveUserData() {
const username = readline.question('Digite o nome de usuário: ');
if (!username) {
console.log('Nome de usuário não pode estar vazio');
return saveUserData();
}
try {
const userData = {
username,
createdAt: new Date().toISOString()
};
fs.writeFileSync(`${username}.json`, JSON.stringify(userData, null, 2));
console.log(`Dados do usuário salvos em ${username}.json`);
} catch (err) {
console.error('Falha ao salvar dados do usuário:', err);
}
}
saveUserData();
Considerações de Desempenho
Operações Síncronas vs. Assíncronas
fs.writeFileSync()
bloqueia o loop de eventos até que a operação seja concluída, o que pode impactar o desempenho em aplicações com alta concorrência:
// Síncrono (bloqueia o loop de eventos)
console.time('writeFileSync');
fs.writeFileSync('large-file.txt', 'X'.repeat(1000000));
console.timeEnd('writeFileSync');
// Assíncrono (não bloqueia o loop de eventos)
console.time('writeFile');
fs.writeFile('large-file-async.txt', 'X'.repeat(1000000), () => {
console.timeEnd('writeFile');
});
console.log('Isso é executado imediatamente enquanto o arquivo está sendo escrito');
Quando Usar fs.writeFileSync()
Use fs.writeFileSync()
quando:
- Estiver escrevendo arquivos pequenos
- Estiver trabalhando em um script ou ferramenta CLI
- O arquivo precisar ser escrito antes de continuar a execução
- Estiver em uma fase de inicialização/configuração
Evite fs.writeFileSync()
quando:
- Trabalhar com arquivos grandes
- Em servidores web com alta concorrência
- Em caminhos de código críticos para o desempenho
- Ao lidar com várias operações de arquivo simultaneamente
Alternativas Modernas
Usando a Sintaxe de Módulos ES
// Sintaxe ESM (requer Node.js 12+)
import { writeFileSync } from 'fs';
import { join } from 'path';
const filePath = join(process.cwd(), 'data.txt');
writeFileSync(filePath, 'Conteúdo usando sintaxe ESM');
Usando a API fs/promises
Para uma abordagem mais moderna com promises mantendo o comportamento síncrono:
// Usando fs/promises com await de nível superior (Node.js 14.8+ com ESM)
import { writeFile } from 'fs/promises';
try {
// Isso ainda é assíncrono, mas com sintaxe mais limpa
await writeFile('example.txt', 'Conteúdo com promises');
console.log('Arquivo escrito com sucesso');
} catch (err) {
console.error('Erro ao escrever arquivo:', err);
}
Considerações de Segurança
Permissões de Arquivo
Esteja atento às permissões de arquivo ao escrever dados sensíveis:
// Definir permissões restritivas para arquivos sensíveis
fs.writeFileSync('credentials.json', JSON.stringify(credentials), {
mode: 0o600 // Leitura/escrita apenas para o proprietário
});
Vulnerabilidades de Travessia de Caminho
Sempre valide e sanitize caminhos de arquivo, especialmente quando vêm da entrada do usuário:
const path = require('path');
const fs = require('fs');
function safeWriteFile(filename, content) {
// Sanitizar nome do arquivo para evitar travessia de caminho
const safeName = path.basename(filename);
const safePath = path.join('./uploads', safeName);
try {
fs.writeFileSync(safePath, content);
return true;
} catch (err) {
console.error('Erro ao escrever arquivo:', err);
return false;
}
}
Solucionando Problemas Comuns
""ENOENT: no such file or directory""
Isso geralmente significa que o diretório não existe:
const fs = require('fs');
const path = require('path');
function writeFileWithDirectoryCreation(filePath, content) {
const directory = path.dirname(filePath);
try {
// Criar diretório se não existir
if (!fs.existsSync(directory)) {
fs.mkdirSync(directory, { recursive: true });
}
// Agora escrever o arquivo
fs.writeFileSync(filePath, content);
return true;
} catch (err) {
console.error('Erro:', err);
return false;
}
}
writeFileWithDirectoryCreation('logs/app/data.log', 'Entrada de log');
""EACCES: permission denied""
Verificar permissões de arquivo e diretório:
try {
fs.writeFileSync('/var/log/app.log', 'Entrada de log');
} catch (err) {
if (err.code === 'EACCES') {
// Tentar escrever em um local diferente
const homeDir = require('os').homedir();
fs.writeFileSync(path.join(homeDir, 'app.log'), 'Entrada de log');
console.log('Escrito no diretório home em vez disso');
}
}
Conclusão
O método fs.writeFileSync()
é uma ferramenta poderosa para lidar com operações de arquivo em aplicações Node.js. Ele fornece uma maneira direta de escrever dados em arquivos de forma síncrona, tornando-o ideal para cenários em que você precisa de conclusão garantida antes de continuar a execução. Ao entender seus parâmetros, tratamento de erros e implicações de desempenho, você pode usar esse método efetivamente em seus projetos, evitando armadilhas comuns.
Lembre-se de considerar a natureza síncrona deste método e usá-lo adequadamente com base nas necessidades da sua aplicação. Para aplicações com alta concorrência ou ao trabalhar com arquivos grandes, considere usar alternativas assíncronas como fs.writeFile()
ou streams.
FAQs
Use fs.writeFileSync() quando precisar de conclusão garantida antes de continuar a execução, tipicamente em scripts, ferramentas CLI ou código de inicialização. Use fs.writeFile() para a maioria dos outros cenários, especialmente em servidores ou aplicações onde o desempenho é importante.
Use a flag 'a' no parâmetro de opções: fs.writeFileSync('log.txt', 'Nova entradan', { flag: 'a' });
Não, ele só pode criar arquivos. Você precisa usar fs.mkdirSync() para criar diretórios primeiro.
Use objetos Buffer: const buffer = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // 'Hello' fs.writeFileSync('binary.dat', buffer);
Não há um limite específico na API, mas escrever arquivos muito grandes de forma síncrona pode bloquear o loop de eventos por muito tempo. Para arquivos maiores que alguns MB, considere usar streams ou métodos assíncronos.
Defina a opção mode: fs.writeFileSync('sensitive.txt', 'dados privados', { mode: 0o600 });