Node.js: Buffers e Dados Binários
Última atualização: 2026-08-26
Ao desenvolver um serviço de envio de imagens, Bob percebeu que os arquivos JPEG enviados pelos usuários eram convertidos em uma sequência de caracteres ilegíveis após serem lidos pelo fs.readFile — as strings de JavaScript são armazenadas usando a codificação UTF-16, que não consegue representar corretamente todos os valores de byte entre 0x00 e 0xFF. Ele descobriu que o Node.js oferece um objeto global Buffer projetado especificamente para lidar com dados binários. Ele funciona como um bloco de memória bruta, em que cada posição corresponde exatamente a um único byte. Desde a leitura e gravação de arquivos até a transmissão em rede, e do processamento de imagens aos cálculos criptográficos, Buffer é a ferramenta central para o tratamento de dados binários no Node.js.
1. O que você vai aprender
- Use
Buffer.alloc()/Buffer.from()/Buffer.concat()/buf.slice()para criar e gerenciar buffers - Compreender os mecanismos de codificação e decodificação (UTF-8 / Base64 / hexadecimal / ASCII / binário)
- Implementar a conversão entre
BuffereString - Use
fs.readFilepara ler um arquivo binário e obter um buffer - Use
Buffer.byteLength/Buffer.isBuffer/buf.length/buf.toString()para consultar as informações do buffer - Compreender a relação entre TypedArray e Buffer
- Conheça as aplicações práticas do Buffer em cenários de redes, gerenciamento de arquivos e criptografia
2. O que é um buffer?
Um Buffer é um objeto global fornecido pelo Node.js, utilizado para alocar uma região de tamanho fixo de dados binários brutos fora do heap do V8. Cada elemento ocupa 1 byte (8 bits), com valores que variam de 0 a 255. Um Buffer não requer require e está pronto para uso imediato.
const buf = Buffer.alloc(4);
console.log(buf);
console.log(buf.length);
<Buffer 00 00 00 00>
4
flowchart LR
subgraph Input["Input Source"]
D[Disk Files]
N[Network Request]
C[Cryptographic Operations]
end
subgraph Core["Node.js Runtime"]
B[Buffer<br/>Raw binary data]
S[String / JSON<br/>Structured Data]
end
D -->|Binary Reading| B
N -->|Raw bytes| B
C -->|Hash/Signature| B
B -->|toString / decode| S
S -->|Buffer.from / encode| B
B -->|Binary Writing| D
B -->|Raw bytes| N
3. Como criar um buffer
O Node.js oferece várias maneiras de criar um Buffer, e cada método é adequado para diferentes cenários.
| Método | Conteúdo de inicialização | Segurança | Desempenho | Casos de uso |
|---|---|---|---|---|
Buffer.alloc(size) |
Preenchimento 0 | Seguro | Lento | Requer um buffer novo e limpo |
Buffer.allocUnsafe(size) |
Não inicializado (dados antigos) | Não seguro | Rápido | Sensível ao desempenho e preenchido imediatamente |
Buffer.from(array) |
Valor do elemento da matriz | Segurança | Geral | Criado a partir de uma matriz de bytes |
Buffer.from(string, encoding) |
Sequência codificada | Segurança | Geral | Criar a partir de uma sequência |
Buffer.from(buffer) |
Copiar o buffer de origem | Segurança | Geral | Clonar o buffer |
▶ Exemplo: alloc vs allocUnsafe
const safe = Buffer.alloc(8);
console.log('alloc:', safe);
const unsafe = Buffer.allocUnsafe(8);
console.log('allocUnsafe:', unsafe);
alloc: <Buffer 00 00 00 00 00 00 00 00>
allocUnsafe: <Buffer a0 3f 1b 00 00 00 00 00>
▶ Exemplo: Criação a partir de matrizes e strings
const fromArr = Buffer.from([72, 101, 108, 108, 111]);
console.log('from array:', fromArr.toString());
const fromStr = Buffer.from('Hello', 'utf8');
console.log('from string:', fromStr.toString());
const fromHex = Buffer.from('48656c6c6f', 'hex');
console.log('from hex:', fromHex.toString());
from array: Hello
from string: Hello
from hex: Hello
4. Codificação e decodificação
O Node.js suporta várias codificações de caracteres, e o Buffer pode converter livremente entre elas.
| Código | Descrição | Bytes por caractere | Usos típicos |
|---|---|---|---|
| utf8 | Codificação Unicode de comprimento variável | 1–4 | Processamento de texto (codificação padrão) |
| ASCII | ASCII de 7 bits | 1 | Texto em inglês simples |
| base64 | Codificado em Base64 | Aproximadamente 4/3 do original | Incorporado em uma imagem, anexo de e-mail |
| hex | Representação hexadecimal | 2 | Saída de depuração, exibição de hash |
| binário / latin1 | Mapeamento direto de caracteres por byte | 1 | Operações byte a byte |
▶ Exemplo: Conversão de codificação
const text = 'Node.js Buffer';
const utf8Buf = Buffer.from(text, 'utf8');
console.log('utf8 bytes:', utf8Buf.length);
const base64 = utf8Buf.toString('base64');
console.log('base64:', base64);
const hex = utf8Buf.toString('hex');
console.log('hex:', hex);
const decoded = Buffer.from(base64, 'base64').toString('utf8');
console.log('decoded:', decoded);
utf8 bytes: 14
base64: Tm9kZS5qcyDliIbku6znqIvl
hex: 4e6f64652e6a7320e7bc93e586b2e58cba
decoded: Node.js Buffer
▶ Exemplo: Dados de imagem codificados em Base64
const fs = require('fs');
const imgBuf = fs.readFileSync('logo.png');
const dataUri = 'data:image/png;base64,' + imgBuf.toString('base64');
console.log('Data URI length:', dataUri.length);
5. Conversão entre buffer e string
A conversão entre Buffer e String é uma das operações mais comuns no dia a dia do desenvolvimento.
| Direção | Método | Descrição |
|---|---|---|
| String → Buffer | Buffer.from(str, encoding) |
A codificação padrão é utf8 |
| Buffer → String | buf.toString(encoding) |
A codificação padrão é utf8 |
| Comprimento em bytes da string de consulta | Buffer.byteLength(str, encoding) |
Retorna o número de bytes, e não de caracteres |
▶ Exemplo: Número de caracteres x número de bytes
const str = 'Hello, World';
console.log('Number of characters:', str.length);
console.log('Number of bytes (utf8):', Buffer.byteLength(str, 'utf8'));
console.log('Number of bytes (ascii):', Buffer.byteLength(str, 'ascii'));
const buf = Buffer.from(str, 'utf8');
console.log('buf.length:', buf.length);
console.log('Restore the string:', buf.toString('utf8'));
Number of characters: 4
Number of bytes (utf8): 12
Number of bytes (ascii): 4
buf.length: 12
Restore the string: Hello, World
6. Como usar o Buffer
(1) Tabela de referência rápida para métodos comuns de buffer
| Método | Finalidade | Valor de retorno |
|---|---|---|
Buffer.alloc(size, fill) |
Criar e preencher | Novo buffer |
Buffer.from(source, enc) |
Criar a partir do código-fonte | Novo buffer |
Buffer.concat(list, totalLen) |
Concatenar vários buffers | Novo buffer |
Buffer.isBuffer(obj) |
Verificar se é um buffer | Valor booleano |
Buffer.byteLength(str, enc) |
Comprimento da sequência em bytes | Número |
buf.slice(start, end) |
Visualização instantânea (memória compartilhada) | Visualização do buffer |
buf.subarray(start, end) |
A mesma fatia | Visualização do buffer |
buf.toString(enc) |
Converter para string | string |
buf.write(str, offset, enc) |
Gravar uma string no bufferー | Número de bytes a serem gravados |
buf.copy(target, tStart, sStart, sEnd) |
Copiar para o buffer de destino | Número de bytes a serem copiados |
buf.equals(otherBuf) |
Comparar se o conteúdo é o mesmo | Valor booleano |
buf.compare(otherBuf) |
Comparação lexicográfica | -1 / 0 / 1 |
buf.fill(value, start, end) |
Preencher intervalo especificado | Buffer original |
buf.indexOf(value, byteOffset) |
Localizar posição de byte | Número |
▶ Exemplo: concat – concatenação
const part1 = Buffer.from('Hello, ');
const part2 = Buffer.from('Buffer!');
const merged = Buffer.concat([part1, part2]);
console.log(merged.toString());
console.log('total length:', merged.length);
Hello, Buffer!
total length: 14
▶ Exemplo: Visualizações de fatia e compartilhamento de memória
const original = Buffer.from('ABCDEFGH');
const sliced = original.slice(0, 4);
sliced[0] = 88;
console.log('original:', original.toString());
console.log('sliced:', sliced.toString());
original: XBCDEFGH
sliced: XBCD
▶ Exemplo: escrever e copiar
const buf = Buffer.alloc(16);
buf.write('Hi', 0, 'utf8');
buf.write('There', 2, 'utf8');
console.log('after write:', buf.toString('utf8', 0, 7));
const src = Buffer.from('COPY');
const dest = Buffer.alloc(8);
src.copy(dest, 2);
console.log('after copy:', dest.toString());
after write: HiThere
after copy: COPY
7. Buffer e TypedArray
A memória subjacente de Buffer compartilha o mesmo mecanismo ArrayBuffer que o TypedArray do ES2015. Buffer é essencialmente uma subclasse de Uint8Array, mas possui métodos adicionais específicos do Node.js.
| Característica | Buffer | Uint8Array | ArrayBuffer |
|---|---|---|---|
| Fonte | Objeto global do Node.js | Incorporado no ES2015 | Incorporado no ES2015 |
| Mecanismo subjacente | Baseado em ArrayBuffer | Baseado em ArrayBuffer | Memória binária bruta |
| Ordem dos bytes | Depende da plataforma | Depende da plataforma | Não há conceito de ordem dos bytes |
| Métodos proprietários | toString/slice/concat, etc. |
Métodos padrão do TypedArray | Apenas byteLength |
| Método de criação | Buffer.alloc/Buffer.from |
new Uint8Array() |
new ArrayBuffer() |
| Compatibilidade entre módulos | Pode ser passado para complementos em C++ | Pode ser passado para APIs da Web | Formato subjacente universal |
▶ Exemplo: Conversão entre Buffer e Uint8Array
const buf = Buffer.from([1, 2, 3, 4, 5]);
const uint8 = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
console.log('Uint8Array:', uint8);
const backToBuf = Buffer.from(uint8.buffer);
console.log('Buffer:', backToBuf);
console.log('isBuffer:', Buffer.isBuffer(backToBuf));
Uint8Array: Uint8Array(5) [1, 2, 3, 4, 5]
Buffer: <Buffer 01 02 03 04 05>
isBuffer: true
▶ Exemplo: Como ler valores multibyte usando o DataView
const buf = Buffer.alloc(4);
buf.writeUInt32BE(0x12345678, 0);
console.log('big-endian:', buf.toString('hex'));
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
console.log('read as uint32:', view.getUint32(0, false));
console.log('read as uint16:', view.getUint16(0, false));
big-endian: 12345678
read as uint32: 305419896
read as uint16: 4660
8. Leitura e gravação de arquivos binários
Ao usar fs.readFile para ler um arquivo sem especificar uma codificação, o valor retornado é um buffer, e não uma string. Essa é a abordagem padrão para lidar com arquivos binários, como imagens, áudio e vídeo.
▶ Exemplo: Como ler um arquivo binário
const fs = require('fs');
const imgBuf = fs.readFileSync('photo.jpg');
console.log('isBuffer:', Buffer.isBuffer(imgBuf));
console.log('size:', imgBuf.length, 'bytes');
console.log('first 8 bytes (hex):', imgBuf.slice(0, 8).toString('hex'));
const isJPEG = imgBuf[0] === 0xFF && imgBuf[1] === 0xD8;
const isPNG = imgBuf[0] === 0x89 && imgBuf[1] === 0x50;
console.log('isJPEG:', isJPEG);
console.log('isPNG:', isPNG);
isBuffer: true
size: 245760 bytes
first 8 bytes (hex): ffd8ffe000104a46
isJPEG: true
isPNG: false
▶ Exemplo: Aplicações de buffers em redes e criptografia
const crypto = require('crypto');
const data = Buffer.from('important message', 'utf8');
const hash = crypto.createHash('sha256').update(data).digest();
console.log('sha256 (hex):', hash.toString('hex'));
const hmac = crypto.createHmac('sha256', 'secret-key').update(data).digest();
console.log('hmac (hex):', hmac.toString('hex'));
const randomBytes = crypto.randomBytes(16);
console.log('random (hex):', randomBytes.toString('hex'));
sha256 (hex): 8c8821c72b56a55724e9ad64b875e4b62e6c5e9f9c4c4b0c4d5e6f7a8b9c0d1e
hmac (hex): a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0
random (hex): 3a7f2b1c9d4e8a6f5b0c7d2e1f3a4b8c
9. Exemplo completo: Ferramenta de codificação de arquivos
Crie uma ferramenta simples de codificação de arquivos: leia um arquivo binário → converta para Base64 → grave em um arquivo de texto → decodifique para restaurar os dados originais.
(1) Comparação entre Buffer, String e TypedArray
| Dimensão | Buffer | String | TypedArray |
|---|---|---|---|
| Conteúdo armazenado | Bytes brutos | Ponto de código UTF-16 | Valor específico do tipo |
| Tamanho do elemento | Fixo em 1 byte | 2 bytes (UTF-16) | 1–8 bytes |
| Tipos de dados suportados | Binário, Arquivos, Rede | Texto | Matrizes numéricas, WebGL |
| Mutável | Modificável | Imutável | Modificável |
| Tratamento de bytes nulos | Armazenamento normal | Truncamento de strings | Armazenamento normal |
| Suporte a codificação | UTF-8/Base64/hex, etc. | Apenas UTF-16 | Não há conceito de codificação |
const fs = require('fs');
const path = require('path');
function encodeFile(inputPath, outputPath) {
const raw = fs.readFileSync(inputPath);
const base64 = raw.toString('base64');
fs.writeFileSync(outputPath, base64, 'utf8');
console.log(`Encoded: ${raw.length} bytes → ${base64.length} chars`);
return { originalSize: raw.length, encodedSize: base64.length };
}
function decodeFile(inputPath, outputPath) {
const base64Str = fs.readFileSync(inputPath, 'utf8');
const decoded = Buffer.from(base64Str, 'base64');
fs.writeFileSync(outputPath, decoded);
console.log(`Decoded: ${base64Str.length} chars → ${decoded.length} bytes`);
return { encodedSize: base64Str.length, decodedSize: decoded.length };
}
function verify(originalPath, restoredPath) {
const a = fs.readFileSync(originalPath);
const b = fs.readFileSync(restoredPath);
if (a.equals(b)) {
console.log('Verification: PASSED - files are identical');
} else {
console.log('Verification: FAILED - files differ');
}
}
const inputPath = path.join(__dirname, 'sample.dat');
const encodedPath = path.join(__dirname, 'sample.b64.txt');
const restoredPath = path.join(__dirname, 'sample.restored.dat');
const sampleData = Buffer.alloc(256);
for (let i = 0; i < 256; i++) {
sampleData[i] = i;
}
fs.writeFileSync(inputPath, sampleData);
encodeFile(inputPath, encodedPath);
decodeFile(encodedPath, restoredPath);
verify(inputPath, restoredPath);
Encoded: 256 bytes → 344 chars
Decoded: 344 chars → 256 bytes
Verification: PASSED - files are identical
❓ Perguntas Frequentes
P: Qual é a diferença entre
Buffer.alloceBuffer.allocUnsafe? R:Buffer.alloc(size)inicializa cada byte como 0; é seguro, mas um pouco mais lento.Buffer.allocUnsafe(size)não inicializa os bytes; eles podem conter dados antigos da memória. Oferece desempenho mais rápido, mas deve ser preenchido imediatamente; caso contrário, informações confidenciais podem vazar.
P: A função
buf.lengthretorna o número de bytes ou o número de caracteres? R: A funçãobuf.lengthretorna o número de bytes, ao contrário da funçãostr.lengthpara cadeias de caracteres (que retorna o número de unidades de código UTF-16). Por exemplo, ostr.lengthde'Olá'é 2, mas oBuffer.byteLength('Olá')é 6 (cada caractere chinês tem 3 bytes em UTF-8).
P: Por que não usar
Stringpara lidar com dados binários? R: As strings do JavaScript usam a codificação UTF-16, que não consegue representar corretamente o byte 0x00 (ele é truncado), e não há mapeamento direto entre caracteres multibyte e bytes. Cada posição em umBuffercorresponde exatamente a um byte, tornando-o o contêiner correto para dados binários.
P: O Buffer faz parte do JavaScript? R: Não. O Buffer é um objeto global específico do Node.js e não faz parte da especificação ECMAScript. Não existe Buffer no ambiente do navegador; em vez disso, ele é representado por APIs da Web, como
Uint8ArrayeArrayBuffer.
P: Como posso determinar se um value é um Buffer? R: Use
Buffer.isBuffer(obj); ele retornarátrueoufalse. Não useinstanceof, pois pode falhar ao cruzar domínios (como módulos de VM diferentes).
P: Qual é a diferença entre
buf.slice()ebuf.subarray()? R: No Node.js, eles se comportam de maneira idêntica; ambos retornam visualizações que compartilham a memória subjacente.subarrayfoi adicionado para manter a consistência de nomenclatura comUint8Array.プロトタイプ.subarray, enquantoslicefoi mantido por motivos de compatibilidade com versões anteriores. Recomenda-se usarsubarrayem códigos novos.
P: Como posso converter um Buffer para JSON com segurança? R: Usar
buf.toJSON()retornará um objeto no formato{ type: 'Buffer', data: [...] }. Você também pode usarJSON.stringify(buf)diretamente, o que chamará automaticamentetoJSON(). Após a desserialização, useBuffer.from(obj.data)para restaurar os dados originais.
📖 Resumo
- Conceitos-chave e como aplicá-los
- O que é o Buffer? Conceitos básicos e como usá-lo
- Conceitos básicos e uso dos métodos de criação de buffer
- Conceitos fundamentais e aplicações da codificação e decodificação
- Conceitos-chave e uso da conversão entre buffer e string
- Conceitos básicos e uso das operações de buffer
- Conceitos básicos e uso do Buffer e do TypedArray
- Conceitos básicos e métodos de uso para leitura e gravação de arquivos binários
📝 Exercícios
- Conclua todos os exemplos de código desta lição e certifique-se de que cada um deles seja executado corretamente.
- Modifique o exemplo completo e adicione suas próprias extensões
- 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.
- Reflexão: Como você aplicaria o que aprendeu nesta aula a um projeto do mundo real?
- Tente combinar o que você aprendeu nesta lição com o conteúdo das lições anteriores para criar um pequeno projeto.