`DataView` в JavaScript

`DataView` в JavaScript

В этой статье объясняется, что такое DataView в JavaScript.

Мы подробно объясним базовое использование DataView и приведем конкретные примеры его применения.

YouTube Video

DataView в JavaScript

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

Что такое DataView?

DataView предоставляет слой представления над объектом ArrayBuffer, позволяя читать и записывать различные типы данных (такие как целые числа, числа с плавающей запятой и символы) с любого смещения в байтах. DataView похож на TypedArray, но его отличительной чертой является возможность указывать порядок байтов (эндиянность) и выполнять детализированные операции на уровне байтов.

Базовый синтаксис DataView

1let buffer = new ArrayBuffer(16);  // Create a 16-byte ArrayBuffer
2let view = new DataView(buffer);    // Manipulate the buffer with a DataView

DataView имеет конструктор, который принимает ArrayBuffer в качестве аргумента. В этом примере создается буфер размером 16 байт, и DataView используется для доступа к этому буферу. С помощью DataView вы можете указывать различные размеры байтов и порядок байтов (big-endian или little-endian) при чтении или записи данных, хранящихся в буфере.

Основные методы DataView

DataView предоставляет методы для чтения и записи значений различных типов данных. Они в основном делятся на методы get для чтения данных и методы set для записи.

Основные методы показаны ниже.

Методы для чтения значений

  • getInt8(byteOffset): Читает 1-байтовое целое число со знаком по указанному смещению.
  • getUint8(byteOffset): Читает 1-байтовое целое число без знака по указанному смещению.
  • getInt16(byteOffset, littleEndian): Читает 2-байтовое целое число со знаком.
  • getUint16(byteOffset, littleEndian): Читает 2-байтовое целое число без знака.
  • getInt32(byteOffset, littleEndian): Читает 4-байтовое целое число со знаком.
  • getUint32(byteOffset, littleEndian): Читает 4-байтовое целое число без знака.
  • getFloat32(byteOffset, littleEndian): Читает 4-байтовое число с плавающей запятой в формате IEEE 754.
  • getFloat64(byteOffset, littleEndian): Читает 8-байтовое число с плавающей запятой в формате IEEE 754.

Методы записи значений

  • setInt8(byteOffset, value): Записывает 1-байтовое знаковое целое число.
  • setUint8(byteOffset, value): Записывает 1-байтовое беззнаковое целое число.
  • setInt16(byteOffset, value, littleEndian): Записывает 2-байтовое знаковое целое число.
  • setUint16(byteOffset, value, littleEndian): Записывает 2-байтовое беззнаковое целое число.
  • setInt32(byteOffset, value, littleEndian): Записывает 4-байтовое знаковое целое число.
  • setUint32(byteOffset, value, littleEndian): Записывает 4-байтовое беззнаковое целое число.
  • setFloat32(byteOffset, value, littleEndian): Записывает 4-байтовое число с плавающей запятой в формате IEEE 754.
  • setFloat64(byteOffset, value, littleEndian): Записывает 8-байтовое число с плавающей запятой в формате IEEE 754.

Используя эти методы, вы можете гибко читать и записывать данные, хранящиеся в ArrayBuffer.

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

Давайте рассмотрим пример манипулирования бинарными данными с помощью DataView.

Пример 1: Запись и чтение 16-битного целого числа

1let buffer = new ArrayBuffer(4);  // Create a 4-byte buffer
2let view = new DataView(buffer);
3
4// Write a 2-byte integer value in little-endian format
5view.setInt16(0, 32767, true);  // byteOffset: 0, value: 32767, littleEndian: true
6
7// Read the data in little-endian format
8let value = view.getInt16(0, true);
9console.log(value);  // Output: 32767
  • В этом примере метод setInt16 используется для записи 16-битного знакового целого числа в формате little-endian, а метод getInt16 считывает это значение в формате little-endian.

Пример 2: Запись и чтение числа с плавающей запятой

1let buffer = new ArrayBuffer(8);  // Create an 8-byte buffer
2let view = new DataView(buffer);
3
4// Write an 8-byte floating-point number
5view.setFloat64(0, 3.14159, false);  // byteOffset: 0, value: 3.14159, bigEndian: false
6
7// Read the data in big-endian format
8let pi = view.getFloat64(0, false);
9console.log(pi);  // Output: 3.14159
  • В этом примере метод setFloat64 используется для записи 64-битного числа с плавающей запятой в формате big-endian, а это значение считывается с помощью getFloat64.

О порядке байтов (Endianness)

Давайте посмотрим пример чтения и записи значений в форматах big-endian и little-endian с помощью DataView.

 1// Example: Handling Endianness with DataView in TypeScript
 2// Create an ArrayBuffer of 4 bytes
 3const buffer = new ArrayBuffer(4);
 4const view = new DataView(buffer);
 5
 6// Store the same number (0x12345678) in both endian formats
 7// By default, DataView uses big-endian
 8view.setUint32(0, 0x12345678); // Big-endian
 9console.log("Big-endian (default):");
10console.log(buffer);
11
12// Overwrite the buffer with little-endian
13view.setUint32(0, 0x12345678, true); // Little-endian
14console.log("Little-endian:");
15console.log(buffer);
16
17// Read values back in both endian modes
18const bigEndianValue = view.getUint32(0); // Big-endian read
19const littleEndianValue = view.getUint32(0, true); // Little-endian read
20
21console.log("Read as Big-endian:", bigEndianValue.toString(16));
22console.log("Read as Little-endian:", littleEndianValue.toString(16));

В методах DataView данные по умолчанию сохраняются в формате big-endian (порядок байтов от старшего к младшему), но формат little-endian может быть указан по желанию. Little-endian меняет порядок байтов на обратный (от младшего к старшему байту). Очень важно правильно обрабатывать порядок байтов данных, поскольку различные системы и сетевые протоколы используют разный порядок байтов.

Разница с TypedArray

Давайте рассмотрим различия между DataView и TypedArray.

 1// Example: TypedArray vs DataView
 2
 3// Create a 8-byte buffer
 4const buffer = new ArrayBuffer(8);
 5
 6// --- Using TypedArray (Int32Array) ---
 7const int32View = new Int32Array(buffer);
 8int32View[0] = 42;
 9int32View[1] = 100;
10
11console.log("TypedArray (Int32Array):");
12console.log(int32View); // Int32Array [42, 100]
13
14// --- Using DataView ---
15const dataView = new DataView(buffer);
16
17// Write different types of data at arbitrary byte offsets
18dataView.setInt8(0, 65);         // 1 byte
19dataView.setUint16(1, 500, true); // 2 bytes, little-endian
20dataView.setFloat32(3, 3.14, true); // 4 bytes, little-endian
21
22console.log("\nDataView:");
23console.log("Int8 at 0:", dataView.getInt8(0));      // 65
24console.log("Uint16 at 1:", dataView.getUint16(1, true)); // 500
25console.log("Float32 at 3:", dataView.getFloat32(3, true)); // 3.14
26
27/*
28Output:
29TypedArray (Int32Array):
30Int32Array [42, 100]
31
32DataView:
33Int8 at 0: 65
34Uint16 at 1: 500
35Float32 at 3: 3.140000104904175
36*/

TypedArray также предоставляет операции с буфером на основе ArrayBuffer, но TypedArray подходит для работы с непрерывными данными фиксированной длины и формата для каждого типа данных. С другой стороны, DataView позволяет гибко работать с различными типами данных и предоставляет возможность контроля над порядком байтов. Таким образом, DataView подходит для анализа и создания сложных бинарных данных.

Резюме

DataView — это мощный API для работы с двоичными данными в JavaScript. Вы можете напрямую обращаться к ArrayBuffer, чтобы считывать и записывать данные, учитывая целые числа, числа с плавающей запятой и различия в порядке байтов (endianness). Это полезно в ситуациях, таких как сетевые коммуникации и разбор форматов файлов, и незаменимо, когда требуется управление на уровне байтов. Используя его вместе с TypedArray, вы можете более эффективно манипулировать бинарными данными.

Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.

YouTube Video