Buffer: бинарные данные
Buffer — встроенный класс Node.js для работы с сырыми бинарными данными (байтами) вне движка V8, используется при работе с файлами, сетевыми потоками, криптографией и бинарными протоколами.
Зачем нужно
JavaScript в браузере работает со строками и числами; бинарные данные появились позже (ArrayBuffer). В Node.js бинарные данные критичны с первого дня: чтение файлов, TCP-сокеты, HTTP-тела, криптография — всё это байты. Buffer — аналог Uint8Array но с дополнительными удобными методами.
Где используется
- Чтение файлов (
fs.readFile) и работа с потоками (Stream) - Криптография (
crypto.hash,crypto.randomBytes) - Кодирование/декодирование строк (UTF-8, Base64, hex)
- Бинарные протоколы (TCP, WebSocket бинарные сообщения)
- Загрузка файлов через Multer (
req.file.buffer)
Основной контент
Создание Buffer
// Из строки
const buf1 = Buffer.from('Hello, Node.js');
const buf2 = Buffer.from('Привет', 'utf8');
const buf3 = Buffer.from('48656c6c6f', 'hex'); // из hex
const buf4 = Buffer.from('SGVsbG8=', 'base64'); // из base64
// Из массива байт
const buf5 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // 'Hello'
// Выделить буфер заданного размера (нули)
const buf6 = Buffer.alloc(10); // 10 байт, заполнен нулями
const buf7 = Buffer.allocUnsafe(10); // быстрее, но может содержать старые данные
// Из ArrayBuffer/TypedArray
const arrayBuffer = new ArrayBuffer(16);
const buf8 = Buffer.from(arrayBuffer);
Конвертация
const buf = Buffer.from('Hello, World!', 'utf8');
// Buffer → строка
buf.toString('utf8'); // 'Hello, World!'
buf.toString('hex'); // '48656c6c6f2c20576f726c6421'
buf.toString('base64'); // 'SGVsbG8sIFdvcmxkIQ=='
buf.toString('ascii'); // для ASCII-только данных
// Buffer → JSON
JSON.stringify(buf); // {"type":"Buffer","data":[72,101,108,...]}
buf.toJSON(); // то же самое
Операции с Buffer
const buf = Buffer.alloc(10);
// Запись
buf.write('Hello', 0, 'utf8'); // записать с позиции 0
buf.writeUInt32BE(12345, 0); // записать 4-байтное число big-endian
// Чтение
const value = buf.readUInt32BE(0); // прочитать 4-байтное число
// Срез (разделяет память!)
const slice = buf.slice(0, 5);
slice[0] = 0xFF; // изменит и buf!
// Безопасная копия
const copy = Buffer.allocUnsafe(5);
buf.copy(copy, 0, 0, 5);
// Объединение
const combined = Buffer.concat([
Buffer.from('Hello, '),
Buffer.from('World!')
]);
Частые паттерны
// Base64 кодирование/декодирование
const encoded = Buffer.from('secret data').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf8');
// Hex для хешей
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('data').digest('hex');
// Генерация случайных байт (для токенов, соли)
const token = crypto.randomBytes(32).toString('hex'); // 64-символьный hex токен
const salt = crypto.randomBytes(16).toString('base64');
// Сравнение буферов (time-safe для crypto)
const isEqual = crypto.timingSafeEqual(buf1, buf2); // не уязвим к timing attack
Buffer и Streams
const { Readable } = require('stream');
// Buffer → Readable Stream
const readable = Readable.from(Buffer.from('hello'));
// Читать файл в Buffer
const fs = require('fs').promises;
const data = await fs.readFile('file.bin'); // возвращает Buffer
console.log(data.length, 'bytes');
Частые ошибки
Buffer.sliceделит память — изменение среза изменяет оригинал; использоватьBuffer.from(buf.slice(0, n))для копииallocUnsafeбез заполнения — содержит случайные данные из памяти; не отправлять клиенту без записи данных- Строки вместо Buffer для бинарных данных — потери при конвертации; хранить бинарные данные как Buffer
- Не указывать кодировку —
toStringпо умолчанию UTF-8, ноfrom('hex string')нужноBuffer.from(str, 'hex')
Связанные темы
Ресурсы
🎓 Источник: Работа с файлами, буферами и файловыми потоками в Node.js
- 📅 2018-10-10 · YouTube ·
eQGBS15vUac - Тезисы:
Buffer.alloc— это аналогmalloc, выделяет и обнуляет памятьBuffer.allocUnsafe— аналог выделения без очистки, быстрее, но содержит «хлам» из памяти процесса- Риск exploit: если отдать
allocUnsafe-буфер без полной перезаписи — клиент получит чужие данные из памяти - Правило: для финансовых и чувствительных данных — только
alloc, никогдаallocUnsafe - Одни и те же данные можно вывести как hex / base64 / utf8 / binary — это разные представления одних байтов
- Цитата:
«alloc — это аналог malloc обычный. А allocUnsafe — аналог выделения памяти без очистки. Если буфер был заполнен нулями, то тут в памяти весь хлам, который остался.»
🎓 Источник: Архив 2018 — Часть 8 Типизированные массивы, буферы, итераторы
- 📅 2020-01-06 · YouTube ·
bFT7VGFfP7o - Тезисы:
- Node
Bufferсейчас — обёртка надUint8Array, до появления TypedArray в языке у ноды был свой Buffer; теперь они почти эквивалентны (Buffer быстрее, иначе копируется) - В основе всех TypedArray —
ArrayBuffer; у Buffer/Uint8Array фиксированный byte-shift Uint8ClampedArray— обрезает значения до 0–255, удобен для пикселей картинокDataViewпозволяет читать/писать разной ширины по произвольному смещениюbuffer.sliceработает по байтам и не понимает Unicode — для строк это решаетStringDecoderв стримах- По буферу можно итерироваться через
for-of,entriesдаёт iterable
- Node
- Цитата:
«Буфер, который сейчас является личным представлением как Uint8Array. Такой же, но с некоторыми отличиями. Он быстрее, он чуть-чуть по-другому копируется.»
🎓 Источник: Работа с файлами, буферами и потоками
- 📅 2018-10-10 · YouTube · [Marp](../../../Documents/TimurShemsedinov/2018-10-10 — Работа с файлами, буферами и файловыми потоками в Node.js (eQGBS15vUac).md)
- Тезисы:
Buffer.alloc(n)vsBuffer.allocUnsafe(n)— второй НЕ зануляет память → утечка чужих данных в новый буфер (быстрее, но опасно)- Буфер в разных кодировках:
buf.toString('hex'),'base64','utf8','binary' - Base64 — 6 бит на символ, +33% размера
Buffer.concat([buf1, buf2])— склейка нескольких буферов в один- Буфер ведёт себя как строка: индексация, length, slice — но возвращает буфер, не строку
BufferНЕ под GC V8 — отдельная C++ память, чтоб не давить на сборку мусора
🎓 Источник: Обзор встроенного Node.js API
- 📅 2018-09-26 · YouTube
- Тезисы: Buffer изменяемый по позициям, склейка чанков из сокета через индексы и
Buffer.concat