ArrayBuffer: примеры (JAVASCRIPT)

Работа с бинарными данными через ArrayBuffer
Раздел: Бинарные данные, Буферы
ArrayBuffer(byteLength: number): ArrayBuffer

Базовое описание ArrayBuffer

ArrayBuffer является низкоуровневым объектом, представляющим буфер с бинарными данными фиксированной длины в памяти. Он используется для работы с бинарными данными при взаимодействии с файлами, сетевыми запросами или графическими API.

Конструктор ArrayBuffer принимает один аргумент:

  • length - размер буфера в байтах (целое число от 0 до 2^53-1).

Созданный буфер инициализируется нулями. ArrayBuffer не позволяет напрямую читать или записывать данные - для этого используются оболочки DataView или типизированные массивы (Uint8Array, Float32Array и другие).

Методы и свойства ArrayBuffer:

  • byteLength - свойство, возвращающее размер буфера в байтах.
  • slice(start, end) - создает новый буфер, копируя данные из исходного от позиции start до end (не включая).
  • isView(view) - статический метод, проверяющий, является ли аргумент view оболочкой для буфера.
  • transfer(oldBuffer, newByteLength) - статический метод для переноса буфера (ECMAScript 2024).

Примеры использования ArrayBuffer

Базовое создание буфера:

const buffer8 = new ArrayBuffer(8);
console.log(buffer8.byteLength);
8

Использование типизированного массива для работы с буфером:

const buffer = new ArrayBuffer(16);
const int32View = new Int32Array(buffer);

for (let i = 0; i < int32View.length; i++) {
  int32View[i] = i * 2;
}

console.log(int32View);
Int32Array(4) [0, 2, 4, 6]

Копирование части буфера:

const original = new ArrayBuffer(16);
const view = new Uint8Array(original);
view[10] = 42;

const sliced = original.slice(8, 12);
console.log(new Uint8Array(sliced));
Uint8Array(4) [0, 0, 42, 0]

Проверка оболочки буфера:

const buffer = new ArrayBuffer(8);
const view = new Float64Array(buffer);

console.log(ArrayBuffer.isView(view));
console.log(ArrayBuffer.isView([1, 2, 3]));
true
false

Похожие функции в JavaScript

SharedArrayBuffer позволяет разделять память между потоками Web Workers. Отличается возможностью совместного использования, но требует дополнительных мер синхронизации.

TypedArray (Uint8Array, Int16Array, Float32Array и другие) предоставляют интерфейс для работы с бинарными данными как с массивами определенного типа. Используются для доступа к данным ArrayBuffer.

DataView предлагает гибкий доступ к данным буфера с возможностью указания порядка байтов (endianness) и смещений в произвольных позициях.

Blob представляет неизменяемые сырые данные, часто используемые для работы с файлами. Может быть создан из ArrayBuffer.

Выбор зависит от задач: ArrayBuffer - для низкоуровневых операций, TypedArray - для типизированного доступа, DataView - для невыровненного доступа, SharedArrayBuffer - для многопоточности.

Типичные ошибки

Попытка прямого доступа к данным:

const buffer = new ArrayBuffer(4);
console.log(buffer[0]);
undefined

Некорректный размер буфера:

try {
  const buffer = new ArrayBuffer(-1);
} catch (e) {
  console.log(e.toString());
}
RangeError: Invalid array buffer length

Изменение размера существующего буфера:

const buffer = new ArrayBuffer(4);
buffer.byteLength = 8;
// Ошибка: свойство byteLength доступно только для чтения

Ошибки при работе с несколькими представлениями:

const buffer = new ArrayBuffer(4);
const view1 = new Uint8Array(buffer);
const view2 = new Uint16Array(buffer);

view1[0] = 255;
console.log(view2[0]);
65280  // Из-за разной интерпретации байтов

Изменения в последних версиях

В ECMAScript 2024 добавлен статический метод ArrayBuffer.transfer() для эффективного переноса или изменения размера буфера.

const buffer1 = new ArrayBuffer(8);
const view = new Uint8Array(buffer1);
view[0] = 42;

const buffer2 = ArrayBuffer.transfer(buffer1, 16);
console.log(buffer1.byteLength);
console.log(buffer2.byteLength);
console.log(new Uint8Array(buffer2)[0]);
0
16
42

Метод transfer позволяет изменить размер буфера, перенося существующие данные. Исходный буфер становится detached (отсоединенным) с нулевой длиной.

Улучшена производительность операций с типизированными массивами в современных движках JavaScript.

Расширенные примеры использования

Чтение бинарного файла через FileReader:

Пример javascript
// В контексте браузера
const fileInput = document.createElement('input');
fileInput.type = 'file';

fileInput.onchange = (e) => {
  const file = e.target.files[0];
  const reader = new FileReader();
  
  reader.onload = (event) => {
    const buffer = event.target.result;
    console.log(`Размер файла: ${buffer.byteLength} байт`);
  };
  
  reader.readAsArrayBuffer(file);
};
// Зависит от выбранного файла

Создание WAV-заголовка:

Пример javascript
function createWavHeader(sampleRate, bitsPerSample, channels, duration) {
  const buffer = new ArrayBuffer(44);
  const view = new DataView(buffer);
  
  // RIFF идентификатор
  view.setUint8(0, 0x52); view.setUint8(1, 0x49);
  view.setUint8(2, 0x46); view.setUint8(3, 0x46);
  
  // Размер файла
  const dataSize = sampleRate * duration * channels * bitsPerSample / 8;
  view.setUint32(4, 36 + dataSize, true);
  
  // WAVE идентификатор
  view.setUint8(8, 0x57); view.setUint8(9, 0x41);
  view.setUint8(10, 0x56); view.setUint8(11, 0x45);
  
  return buffer;
}

const header = createWavHeader(44100, 16, 2, 5);
console.log(header.byteLength);
44

Шифрование XOR:

Пример javascript
function xorEncrypt(buffer, key) {
  const result = new Uint8Array(buffer.byteLength);
  const keyArray = new TextEncoder().encode(key);
  
  for (let i = 0; i < buffer.byteLength; i++) {
    result[i] = buffer[i] ^ keyArray[i % keyArray.length];
  }
  
  return result.buffer;
}

const data = new Uint8Array([65, 66, 67, 68]);
const encrypted = xorEncrypt(data.buffer, 'secret');
console.log(new Uint8Array(encrypted));
Uint8Array(4) [18, 1, 14, 23]

Работа с WebSocket и бинарными данными:

Пример javascript
// Клиентская часть
const socket = new WebSocket('ws://example.com');
socket.binaryType = 'arraybuffer';

socket.onmessage = (event) => {
  if (event.data instanceof ArrayBuffer) {
    const view = new Float32Array(event.data);
    console.log('Получено чисел с плавающей точкой:', view.length);
  }
};

// Отправка бинарных данных
const buffer = new ArrayBuffer(32);
const floatArray = new Float32Array(buffer);
floatArray[0] = 3.14159;
socket.send(buffer);
// Зависит от серверной реализации

Альтернативы в других языках программирования

Python: модуль array и тип bytearray.

import array
arr = array.array('i', [1, 2, 3, 4])
print(arr.tobytes())
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'

PHP: ресурс stream и функции упаковки/распаковки.

$data = pack('i*', 1, 2, 3, 4);
echo bin2hex($data);
01000000020000000300000004000000

C: указатели и динамическое выделение памяти.

#include 
#include 

int main() {
    int *buffer = (int*)malloc(4 * sizeof(int));
    for(int i = 0; i < 4; i++) buffer[i] = i + 1;
    printf("%d", buffer[2]);
    free(buffer);
    return 0;
}
3

MySQL: тип данных BLOB для хранения бинарных данных.

Основные отличия: в JavaScript ArrayBuffer управляется сборщиком мусора, имеет строгую типизацию через оболочки и ограниченную арифметику указателей.

JS ArrayBuffer function comments

En
ArrayBuffer Represents a raw binary data buffer of fixed length.