`DataView` w języku JavaScript

`DataView` w języku JavaScript

Ten artykuł wyjaśnia DataView w JavaScript.

Wyjaśnimy szczegółowo podstawowe zastosowanie DataView oraz konkretne przykłady jego użycia.

YouTube Video

DataView w języku JavaScript

DataView w JavaScript jest wygodnym API do manipulacji danymi przechowywanymi w buforze (ArrayBuffer) w różnych formatach. Umożliwia to elastyczne i wydajne odczytywanie i zapisywanie danych binarnych, odgrywając ważną rolę w komunikacji sieciowej, przetwarzaniu plików i interakcji z WebAssembly.

Czym jest DataView?

DataView zapewnia warstwę widoku nad obiektem ArrayBuffer, umożliwiając odczyt i zapis różnych typów danych (takich jak liczby całkowite, liczby zmiennoprzecinkowe i znaki) od dowolnego przesunięcia bajtów. DataView jest podobny do TypedArray, ale charakteryzuje się możliwością określenia porządku bajtów (endianness) oraz wykonywania szczegółowych operacji na poziomie bajtów.

Podstawowa składnia DataView

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

DataView posiada konstruktor, który przyjmuje ArrayBuffer jako argument. W tym przykładzie tworzony jest 16-bajtowy bufor, a DataView jest używany do uzyskania dostępu do tego buforu. Korzystając z DataView, możesz określić różne rozmiary bajtów i porządek bajtów (big-endian lub little-endian) podczas odczytu lub zapisu danych przechowywanych w buforze.

Podstawowe metody DataView

DataView oferuje metody do odczytu i zapisu wartości różnych typów danych. Są one głównie podzielone na metody get do odczytu danych oraz set do zapisu.

Główne metody przedstawiono poniżej.

Metody odczytu wartości

  • getInt8(byteOffset): Odczytuje 1-bajtową liczbę całkowitą ze znakiem na określonym przesunięciu.
  • getUint8(byteOffset): Odczytuje 1-bajtową liczbę całkowitą bez znaku na określonym przesunięciu.
  • getInt16(byteOffset, littleEndian): Odczytuje 2-bajtową liczbę całkowitą ze znakiem.
  • getUint16(byteOffset, littleEndian): Odczytuje 2-bajtową liczbę całkowitą bez znaku.
  • getInt32(byteOffset, littleEndian): Odczytuje 4-bajtową liczbę całkowitą ze znakiem.
  • getUint32(byteOffset, littleEndian): Odczytuje 4-bajtową liczbę całkowitą bez znaku.
  • getFloat32(byteOffset, littleEndian): Odczytuje 4-bajtową liczbę zmiennoprzecinkową IEEE 754.
  • getFloat64(byteOffset, littleEndian): Odczytuje 8-bajtową liczbę zmiennoprzecinkową w formacie IEEE 754.

Metody zapisu wartości

  • setInt8(byteOffset, value): Zapisuje 1-bajtową liczbę całkowitą ze znakiem.
  • setUint8(byteOffset, value): Zapisuje 1-bajtową liczbę całkowitą bez znaku.
  • setInt16(byteOffset, value, littleEndian): Zapisuje 2-bajtową liczbę całkowitą ze znakiem.
  • setUint16(byteOffset, value, littleEndian): Zapisuje 2-bajtową liczbę całkowitą bez znaku.
  • setInt32(byteOffset, value, littleEndian): Zapisuje 4-bajtową liczbę całkowitą ze znakiem.
  • setUint32(byteOffset, value, littleEndian): Zapisuje 4-bajtową liczbę całkowitą bez znaku.
  • setFloat32(byteOffset, value, littleEndian): Zapisuje 4-bajtową liczbę zmiennoprzecinkową w formacie IEEE 754.
  • setFloat64(byteOffset, value, littleEndian): Zapisuje 8-bajtową liczbę zmiennoprzecinkową w formacie IEEE 754.

Dzięki tym metodom można elastycznie odczytywać i zapisywać dane przechowywane w ArrayBuffer.

Przykład użycia DataView

Przyjrzyjmy się przykładowi manipulowania danymi binarnymi za pomocą DataView.

Przykład 1: Zapis i odczyt 16-bitowej liczby całkowitej

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
  • W tym przykładzie metoda setInt16 służy do zapisu 16-bitowej liczby całkowitej ze znakiem w formacie little-endian, a metoda getInt16 odczytuje tę wartość również w formacie little-endian.

Przykład 2: Zapis i odczyt liczby zmiennoprzecinkowej

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
  • W tym przykładzie metoda setFloat64 służy do zapisu 64-bitowej liczby zmiennoprzecinkowej w formacie big-endian, a odczytywana jest za pomocą getFloat64.

O końcowości (Endianness)

Zobaczmy przykład odczytywania i zapisywania wartości zarówno w formacie big-endian, jak i little-endian za pomocą 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));

W metodach DataView dane są domyślnie przechowywane w formacie big-endian (kolejność bajtów od najbardziej znaczącego do najmniej znaczącego bajtu), ale można opcjonalnie określić format little-endian. Little-endian odwraca kolejność bajtów (od najmniej znaczącego do najbardziej znaczącego bajtu). Ważne jest prawidłowe obsługiwanie kolejności bajtów (endianness) danych, ponieważ różne systemy i protokoły sieciowe używają różnych sposobów zapisywania bajtów.

Różnica w porównaniu do TypedArray

Przyjrzyjmy się różnicom pomiędzy DataView a 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 również umożliwia operacje na buforach bazujących na ArrayBuffer, jednakże TypedArray nadaje się do operacji na danych ciągłych o ustalonej długości i formacie dla każdego typu danych. Z kolei DataView pozwala elastycznie operować na różnych typach danych, a także umożliwia kontrolę nad końcowością. Dlatego DataView nadaje się do parsowania i konstruowania złożonych danych binarnych.

Podsumowanie

DataView to potężne API do obsługi danych binarnych w JavaScript. Możesz bezpośrednio uzyskać dostęp do ArrayBuffer, aby odczytywać i zapisywać dane, uwzględniając liczby całkowite, liczby zmiennoprzecinkowe oraz różnice w kolejności bajtów (endianness). Jest przydatny w sytuacjach takich jak komunikacja sieciowa i analiza formatów plików, a także niezbędny, gdy wymagana jest kontrola na poziomie bajtów. Używając go razem z TypedArray, możesz wydajniej manipulować danymi binarnymi.

Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.

YouTube Video