`DataView` sa TypeScript

`DataView` sa TypeScript

Ipinaliwanag ng artikulong ito ang DataView sa TypeScript.

Ipapaliwanag namin ang DataView sa TypeScript, mula sa mga batayan hanggang sa praktikal na paggamit, hakbang-hakbang.

YouTube Video

DataView sa TypeScript

Sa paggamit ng DataView sa TypeScript, maaari kang magsagawa ng detalyadong pagbabasa at pagsusulat ng bawat byte sa isang ArrayBuffer. Ang DataView ay napakakapal-halaga para sa mababang-level na binary processing gaya ng pagpapatupad ng protocol, pagsusuri ng binary file, at pagpapadala/pagtanggap ng binary data sa pamamagitan ng WebSocket.

Pangunahing Konsepto: Pagkakaiba sa pagitan ng ArrayBuffer, TypedArray, at DataView

Ang ArrayBuffer ay pangunahing istruktura ng datos na ginagamit upang mag-imbak ng sunod-sunod na bytes na may takdang haba. Ang mga TypedArray tulad ng Uint8Array ay mga view na tinitingnan ang buffer bilang isang array ng spesipikong uri, kung saan ang bawat elemento ay may takdang uri.

Sa kabilang banda, ang DataView ay isang flexible na view na nagbibigay-daan sa iyo na magbasa at magsulat ng anumang uri ng datos sa kahit anong offset na posisyon. Dahil hindi ito nangangailangan ng fixed na mga uri ng datos at nagbibigay-daan sa detalyadong kontrol sa byte level, ito ay angkop para sa pagsusuri ng mga binary protocol at mababang-antaspagpoproseso.

Ang sumusunod ay isang halimbawa ng paglikha ng ArrayBuffer at pagkatapos ay paggawa ng Uint8Array at DataView mula rito.

 1// Create an ArrayBuffer (8 bytes)
 2const buffer = new ArrayBuffer(8);
 3
 4// Create a Uint8Array view (easy to manipulate individual bytes)
 5const u8 = new Uint8Array(buffer);
 6u8[0] = 0x12;
 7u8[1] = 0x34;
 8
 9// Create a DataView (allows reading/writing any type at any offset)
10const dv = new DataView(buffer);
11
12// Read a 16-bit unsigned integer (big-endian assumed if second argument is omitted)
13console.log(dv.getUint16(0)); // 0x1234
  • Sa code na ito, dalawang magkaibang uri ng view—Uint8Array at DataView—ang ginagamit nang sabay sa isang buffer. Sa paggamit ng DataView, flexible mong mababasa at maisusulat ang mga halaga sa pamamagitan ng pagtukoy ng offset at endianness.

Pangunahing Paraan ng DataView

Ang DataView ay interface para manipulahin ang isang ArrayBuffer sa byte level, at nagbibigay ng mga paraan upang magbasa at magsulat ng iba't ibang uri tulad ng integer at floating-point number.

Ang mga pangunahing paraan ay ang mga sumusunod:.

  • Pagbasa: getUint8, getInt8, getUint16, getInt16, getUint32, getInt32, getFloat32, getFloat64
  • Pagsusulat: setUint8, setInt8, setUint16, setInt16, setUint32, setInt32, setFloat32, setFloat64

Lahat ng mga paraang ito ay tumatanggap ng 'byte offset' bilang unang argumento: ang get ay bumabasa ng halaga sa posisyong iyon, at ang set ay nagsusulat ng halaga sa parehong posisyon. Maaari mo ring tukuyin ang endianness gamit ang ikalawang argumento kapag humahawak ng 16-, 32-, o 64-bit na data. Sa aktwal na paggamit, pinakaligtas na lagi mong tukuyin ang endianness ayon sa spec ng data.

Ipinapakita ng sumusunod na halimbawa kung paano magsulat ng 32-bit integer at 32-bit floating-point number gamit ang little endian format sa isang buffer, at pagkatapos ay basahin ito pabalik sa parehong format.

 1const buf = new ArrayBuffer(12); // Enough space for integer + float
 2const view = new DataView(buf);
 3
 4// Write a 32-bit unsigned integer at offset 0 (little-endian)
 5view.setUint32(0, 305419896, true); // 305419896 = 0x12345678
 6
 7// Read the same 32-bit unsigned integer back from offset 0 (little-endian)
 8const intVal = view.getUint32(0, true);
 9console.log(intVal); // 305419896
10
11// Write a 32-bit floating number at offset 4 (little-endian)
12view.setFloat32(4, 3.1415926, true);
13
14// Read the 32-bit floating number back from offset 4 (little-endian)
15const floatVal = view.getFloat32(4, true);
16console.log(floatVal); // 3.1415926 (approx)
  • Sa malinaw na pagtukoy ng endianness, nakakatiyak kang compatible ito sa iba't ibang platform at binary specification.

Tungkol sa Endianness (Kaayusan ng Byte)

Ang ilang mga protocol, tulad ng ginagamit sa networking, ay gumagamit ng big-endian, habang karamihan sa mga CPU at file format ay nakabatay sa little-endian na disenyo. Sa DataView, kapag ang ikalawang argumento ay true, tinatrato nito ang datos bilang little endian; kung ito ay false o hindi nilagay, tinatrato bilang big endian.

Sa sumusunod na halimbawa, makikita mo kung paano nagbabago ang byte array sa memory kapag nagsusulat ng parehong numero gamit ang big-endian at little-endian na mga format.

 1const b = new ArrayBuffer(4);
 2const a = new Uint8Array(b);
 3const dv = new DataView(b);
 4
 5// Write in big-endian order
 6dv.setUint32(0, 0x0A0B0C0D, false); // big-endian
 7console.log([...a]); // [10, 11, 12, 13]
 8
 9// Write the same value in little-endian order
10dv.setUint32(0, 0x0A0B0C0D, true); // little-endian
11console.log([...a]); // [13, 12, 11, 10]
  • Ang pag-unawa kung paano nagbabago ang pagkakaayos ng bytes sa pagitan ng big endian at little endian ay mas magpapadali sa pagsusuri ng communication data o binary formats.

Pagpasok/Paglabas ng String (Gamit ang TextEncoder at Decoder nang magkasama)

Magaling ang DataView para sa pagbabasa at pagsusulat ng mga numero, pero hindi nito direktang nae-handle ang mga string. Karaniwan ang i-encode muna ang string gamit ang TextEncoder o TextDecoder (tulad ng UTF-8), saka ito ilalagay sa buffer sa pamamagitan ng Uint8Array. Narito ang isang halimbawa ng pagsusulat ng UTF-8 string sa buffer at pagkatapos ay basahin ulit ito.

 1const encoder = new TextEncoder();
 2const decoder = new TextDecoder();
 3
 4const str = "\u3053\u3093\u306b\u3061\u306f";
 5const encoded = encoder.encode(str); // Uint8Array (UTF-8 encoded bytes)
 6
 7// Create a buffer and write the encoded string bytes into it
 8const buf2 = new ArrayBuffer(encoded.length);
 9const u8v = new Uint8Array(buf2);
10u8v.set(encoded);
11
12// Read the bytes and decode them back into a string
13const decodedStr = decoder.decode(new Uint8Array(buf2));
14console.log(decodedStr);
  • Sa pamamagitan ng pag-convert ng string sa binary, at kung kinakailangan, lagyan ng haba sa unahan, maaari mong maiimbak ang string na may pabago-bagong haba.

Praktikal na Halimbawa: Pag-encode/Pag-decode ng Custom na Binary Format

Sa ibaba, nagde-define tayo ng isang simpleng format ng mensahe na naglalaman ng version number, ID, at pangalan. Nagpapatupad tayo ng encoding na proseso para gawing binary data ang mga mensahe, at decoding na proseso para maibalik sa orihinal na object mula sa binary. Sa format ng mensaheng ito, ang unang byte ay naglalaman ng bersyon, ang susunod na 4 na byte ay para sa ID sa little-endian na format, ang sumusunod na byte ay para sa haba ng pangalan, at sa huli ay ang pangalan na naka-encode sa UTF-8.

 1// Encode an object into a binary message
 2function encodeMessage(msg: { version: number; id: number; name: string }): ArrayBuffer {
 3  const encoder = new TextEncoder();
 4  const nameBytes = encoder.encode(msg.name);
 5  const total = 1 + 4 + 1 + nameBytes.length;
 6  const buf = new ArrayBuffer(total);
 7  const dv = new DataView(buf);
 8  let offset = 0;
 9
10  dv.setUint8(offset, msg.version); offset += 1;      // write version
11  dv.setUint32(offset, msg.id, true); offset += 4;    // write ID (little-endian)
12  dv.setUint8(offset, nameBytes.length); offset += 1; // write name length
13
14  // write name bytes
15  new Uint8Array(buf, offset).set(nameBytes);
16  return buf;
17}
18
19// Decode a binary message back into an object
20function decodeMessage(buf: ArrayBuffer) {
21  const dv = new DataView(buf);
22  let offset = 0;
23
24  const version = dv.getUint8(offset); offset += 1;   // read version
25  const id = dv.getUint32(offset, true); offset += 4; // read ID (little-endian)
26  const nameLen = dv.getUint8(offset); offset += 1;   // read name length
27
28  // extract name bytes
29  const nameBytes = new Uint8Array(buf, offset, nameLen);
30  const decoder = new TextDecoder();
31  // decode UTF-8 string
32  const name = decoder.decode(nameBytes);
33
34  return { version, id, name };
35}
36
37// Example usage
38const packed = encodeMessage({ version: 1, id: 42, name: "Alice" });
39const unpacked = decodeMessage(packed);
40console.log(unpacked); // { version: 1, id: 42, name: "Alice" }
  • Ito ay isang tipikal na implementasyon para sa simpleng format ng mensahe na may string na pabago-bago ang haba, at maaaring magamit sa maraming praktikal na sitwasyon tulad ng network communication o custom na disenyo ng binary file.

Mga Paalala at Pinakamainam na Gawi

Kapag nagtatrabaho gamit ang binary data sa DataView, may ilang mga praktikal na bagay na dapat isaalang-alang bukod sa simpleng pagbabasa at pagsusulat ng mga halaga—tulad ng kaligtasan, tuloy-tuloy na paggamit ng endianness, at tamang paghawak ng mga uri. Lalo na kapag humahawak ng binary data na nagmula sa labas o malalaking integer, mahalagang idisenyo ang iyong code para maiwasan ang maling pagbabasa at buffer overrun. Narito ang ilang mga kapaki-pakinabang na punto na dapat tandaan para sa praktikal na paggamit.

  • Pagsusuri ng Hangganan Magkakaroon ng exception ang DataView kapag ang offset o laki ay lumagpas sa hangganan ng buffer. Laging suriin ang haba kapag humahawak ng hindi mapagkakatiwalaang binary data.

  • Laging Tukuyin ang Endianness Laging maging malinaw at pare-pareho sa pagtukoy kung little endian o big endian sa iyong code.

  • Pagkakapareho ng Uri Ang mga numero sa JavaScript ay 64-bit IEEE-754 floating-point values. Ang mga paraan tulad ng getUint32 ay maaaring gamitin nang tama, ngunit walang getUint64, kaya't kailangan ng espesyal na paraan para sa 64-bit integer.

  • Paghawak ng 64-bit na Integer Para sa 64-bit integer, kailangang gumamit ng BigInt o manu-manong hatiin ang halaga sa mataas at mababang 32-bit na bahagi. Narito ang simpleng halimbawa ng pagbabasa ng 64-bit unsigned integer.

1function getUint64(dv: DataView, offset: number, littleEndian = true): bigint {
2  const low = BigInt(dv.getUint32(offset, littleEndian));
3  const high = BigInt(dv.getUint32(offset + 4, littleEndian));
4  return littleEndian ? (high << 32n) | low : (low << 32n) | high;
5}
  • Sa paggamit ng BigInt, ligtas mo ring mahahawakan ang integer na mas malaki pa sa 64 bits.

Paggamit sa Node.js (Pakikisalamuha sa Buffer)

Bagaman madalas gamitin ang Buffer sa Node.js, madali ring mag-convert sa pagitan ng ArrayBuffer at DataView. Gamitin ang buffer property ng mga Buffer object o ang Uint8Array constructor para sa conversion.

1// Node.js: Buffer -> ArrayBuffer
2const nodeBuf = Buffer.from([1,2,3,4]);
3const arrBuf = nodeBuf.buffer.slice(nodeBuf.byteOffset, nodeBuf.byteOffset + nodeBuf.byteLength);
4const dvNode = new DataView(arrBuf);
5console.log(dvNode.getUint16(0));
  • Maari itong gamitin bilang kasangkapan para sa pagpapalitan ng binary data sa pagitan ng Node.js at mga browser.

Buod

Ang DataView ay makapangyarihang mekanismo para sa malayang pagbabasa at pagsusulat ng binary data—lalo na kung kailangan ng flexible na kontrol gaya ng pagtukoy ng endianness at pag-access sa anumang posisyon. Sa pagsasama ng ArrayBuffer, TypedArray, at DataView, flexible at tama mong mahahawakan ang binary data gamit ang TypeScript, na nagpapahintulot ng malawak na saklaw ng paggamit mula protokol hanggang pagsusuri ng file. Sa pagsasama rin ng string encoding at paghawak ng 64-bit integer kung kinakailangan, mas higit mong magagawa ang praktikal na binary operations.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video