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

DataView в JavaScript: руководство и практические примеры
Раздел: Бинарные данные, Представление
DataView(buffer: ArrayBuffer, byteOffset?: number, byteLength?: number): DataView

Общее описание функции DataView

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

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

  • buffer: Обязательный. Существующий объект ArrayBuffer, с которым будет работать представление.
  • byteOffset (необязательный): Смещение в байтах от начала буфера, с которого начнется представление. По умолчанию 0.
  • byteLength (необязательный): Количество байтов, которое будет охватывать представление. По умолчанию — длина буфера минус смещение.

DataView не возвращает новое значение, а создает объект-представление для переданного буфера. Для чтения и записи данных он предоставляет методы вида getInt8(offset), setUint32(offset, value, littleEndian) и другие для различных типов данных (Int8, Uint8, Int16, Uint16, Int32, Uint32, Float32, Float64, BigInt64, BigUint64). Третий необязательный параметр littleEndian указывает порядок байтов (по умолчанию false — big-endian).

Базовые примеры использования DataView

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

const buffer = new ArrayBuffer(16); // Буфер на 16 байт
const view = new DataView(buffer);
// Создан DataView, связанный с буфером.

Запись и чтение 32-битного целого числа:

view.setInt32(0, 267); // Запись числа 267 в первые 4 байта
const result = view.getInt32(0); // Чтение числа обратно
console.log(result);
267

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

view.setUint16(0, 0x1234, true); // Запись в little-endian
const le = view.getUint16(0, true);
const be = view.getUint16(0, false);
console.log('LE:', le.toString(16), 'BE:', be.toString(16));
LE: 1234 BE: 3412

Работа с числами с плавающей точкой:

view.setFloat64(0, Math.PI);
console.log(view.getFloat64(0));
3.141592653589793

Похожие функции и интерфейсы в JavaScript

В JavaScript для работы с бинарными данными также существуют типизированные массивы (например, Int32Array, Float64Array). Они представляют собой «виды» (views) на ArrayBuffer, но в отличие от DataView, имеют фиксированный тип элементов и доступны как обычные массивы. DataView является более гибким решением, когда в одном буфере смешаны данные разных типов и разного порядка байтов. Типизированные массивы используют порядок байтов платформы, на которой выполняется код, что может привести к несовместимости. Выбор зависит от задачи: для однородных данных удобнее типизированный массив, для неоднородных или при необходимости строгого контроля порядка байтов — DataView.

Распространенные ошибки при работе с DataView

Ошибка выхода за границы буфера при чтении или записи.

const smallBuffer = new ArrayBuffer(2);
const smallView = new DataView(smallBuffer);
// Попытка прочитать 4 байта из буфера размером 2 байта
console.log(smallView.getInt32(0));
RangeError: Offset is outside the bounds of the DataView

Несоответствие ожидаемого порядка байтов при чтении данных из внешнего источника.

// Предположим, данные пришли в формате big-endian
view.setUint32(0, 0x12345678); // По умолчанию big-endian (false)
// Ошибочное чтение как little-endian
console.log('Ошибка:', view.getUint32(0, true).toString(16));
// Правильное чтение
console.log('Правильно:', view.getUint32(0, false).toString(16));
Ошибка: 78563412
Правильно: 12345678

Путаница между знаковыми и беззнаковыми типами при работе с большими числами.

view.setUint8(0, 255); // Беззнаковый максимум для 1 байта
console.log('Беззнаковый:', view.getUint8(0));
console.log('Знаковый:', view.getInt8(0)); // Интерпретация байта как знакового
Беззнаковый: 255
Знаковый: -1

Изменения в DataView

Спецификация DataView долгое время оставалась стабильной. Основные изменения связаны с добавлением поддержки больших целых чисел (BigInt) в современных стандартах JavaScript (ES2020). Появились методы getBigInt64(), getBigUint64(), setBigInt64() и setBigUint64() для работы с 64-битными целыми числами, которые выходят за пределы безопасного диапазона чисел Number. Это позволяет точно работать с 64-битными значениями из бинарных протоколов или файлов.

Расширенные примеры применения DataView

Парсинг простого бинарного заголовка файла, содержащего разные типы данных.

Пример javascript
// Представим структуру: [Uint16 id, Float32 x, Float32 y, Uint8 flags]
const headerBuffer = new ArrayBuffer(2 + 4 + 4 + 1);
const headerView = new DataView(headerBuffer);
// Заполнение данными (предположим, все в little-endian)
headerView.setUint16(0, 1000, true);
headerView.setFloat32(2, 3.14, true);
headerView.setFloat32(6, -2.71, true);
headerView.setUint8(10, 0x05);
// Парсинг
const parsed = {
    id: headerView.getUint16(0, true),
    x: headerView.getFloat32(2, true),
    y: headerView.getFloat32(6, true),
    flags: headerView.getUint8(10)
};
console.log(parsed);
{ id: 1000, x: 3.14, y: -2.71, flags: 5 }

Преобразование строки в последовательность байт в UTF-8 и обратно с использованием DataView.

Пример javascript
function stringToUtf8Buffer(str) {
    const encoder = new TextEncoder(); // Более современный API
    return encoder.encode(str).buffer;
}
function utf8BufferToString(buffer) {
    const view = new DataView(buffer);
    // Для простоты - чтение как последовательность байт и декодирование
    const decoder = new TextDecoder();
    return decoder.decode(view); // DataView передается как ArrayBufferView
}
const testStr = 'Привет, мир!';
const buf = stringToUtf8Buffer(testStr);
console.log('Буфер размером:', buf.byteLength, 'байт');
console.log('Восстановлено:', utf8BufferToString(buf));
Буфер размером: 20 байт
Восстановлено: Привет, мир!

Чтение 64-битного целого (BigInt) из буфера.

Пример javascript
const bigBuffer = new ArrayBuffer(16);
const bigView = new DataView(bigBuffer);
const hugeNumber = BigInt('9007199254740993'); // Число больше Number.MAX_SAFE_INTEGER
bigView.setBigInt64(0, hugeNumber, true);
const readValue = bigView.getBigInt64(0, true);
console.log('Записано:', hugeNumber);
console.log('Прочитано:', readValue);
console.log('Совпадение:', hugeNumber === readValue);
Записано: 9007199254740993n
Прочитано: 9007199254740993n
Совпадение: true

Работа с частью буфера через смещение и длину.

Пример javascript
const mainBuffer = new ArrayBuffer(100);
// Создаем представление только на часть буфера (байты с 10 по 29)
const partialView = new DataView(mainBuffer, 10, 20);
console.log('byteLength partialView:', partialView.byteLength);
console.log('byteOffset partialView:', partialView.byteOffset);
// Запись в эту часть не затронет другие области mainBuffer
partialView.setInt32(0, 42); // Записываем по смещению 0 внутри partialView
// Для проверки создадим еще одно представление на весь буфер
const fullView = new DataView(mainBuffer);
console.log('Значение в основном буфере по смещению 10:', fullView.getInt32(10));
byteLength partialView: 20
byteOffset partialView: 10
Значение в основном буфере по смещению 10: 42

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

В Python для работы со структурированными бинарными данными используется модуль struct.

import struct
# Упаковка числа в байты (little-endian)
packed = struct.pack('
b'\x0b\x01\x00\x00'
267

В PHP существуют функции pack() и unpack().

$packed = pack('V', 267); // 'V' - unsigned long (always 32 bit, little endian)
echo bin2hex($packed), "\n";
$unpacked = unpack('V', $packed)[1];
echo $unpacked;
0b010000
267

В C для подобных целей часто применяют приведение типов указателей или union.

#include <stdint.h>
#include <stdio.h>
int main() {
    uint8_t buffer[4] = {0x0B, 0x01, 0x00, 0x00};
    // Интерпретация байтов как 32-битного целого (little-endian)
    uint32_t value = *(uint32_t*)buffer;
    printf("%u\n", value); // 267
    return 0;
}
267

В MySQL для преобразования данных можно использовать функции типа CAST() или HEX(), но низкоуровневая работа с байтами не является типичной задачей для СУБД.

JS DataView function comments

En
DataView Provides a low-level interface for reading and writing multiple number types in an ArrayBuffer.