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
Парсинг простого бинарного заголовка файла, содержащего разные типы данных.
// Представим структуру: [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.
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) из буфера.
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
Работа с частью буфера через смещение и длину.
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(), но низкоуровневая работа с байтами не является типичной задачей для СУБД.