`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 metodagetInt16
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.