`DataView` di TypeScript

`DataView` di TypeScript

Artikel ini menjelaskan DataView di TypeScript.

Kami akan menjelaskan DataView di TypeScript, mulai dari dasar hingga penggunaan praktis, secara bertahap.

YouTube Video

DataView di TypeScript

Dengan menggunakan DataView di TypeScript, Anda dapat melakukan operasi baca dan tulis pada tingkat byte secara detail pada sebuah ArrayBuffer. DataView sangat berguna untuk pemrosesan biner tingkat rendah seperti implementasi protokol, analisis file biner, dan pengiriman/penerimaan data biner melalui WebSocket.

Konsep Dasar: Perbedaan antara ArrayBuffer, TypedArray, dan DataView

ArrayBuffer adalah struktur data dasar yang digunakan untuk menyimpan urutan byte dengan panjang tetap. TypedArray seperti Uint8Array adalah tampilan yang memperlakukan buffer sebagai array dari tipe tertentu, di mana setiap elemen memiliki tipe yang tetap.

Di sisi lain, DataView adalah tampilan yang fleksibel yang memungkinkan Anda membaca dan menulis nilai dari tipe data apa pun pada posisi offset mana pun. Karena tidak mengasumsikan tipe tetap dan memungkinkan kontrol yang sangat detail pada tingkat byte, ini cocok untuk menganalisis protokol biner dan pemrosesan tingkat rendah.

Berikut adalah contoh membuat sebuah ArrayBuffer dan kemudian membuat Uint8Array serta DataView darinya.

 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
  • Pada kode ini, dua jenis tampilan yang berbeda—Uint8Array dan DataView—digunakan secara bersamaan pada satu buffer. Dengan menggunakan DataView, Anda dapat secara fleksibel membaca dan menulis nilai dengan menentukan offset dan endianness secara sewenang-wenang.

Metode Utama dari DataView

DataView adalah antarmuka untuk memanipulasi ArrayBuffer pada tingkat byte, dan menyediakan metode untuk membaca dan menulis berbagai tipe seperti integer dan angka floating-point.

Metode utamanya adalah sebagai berikut:.

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

Semua metode ini menerima 'byte offset' sebagai argumen pertama: get membaca nilai di posisi tersebut, dan set menulis nilai ke posisi tersebut. Anda juga dapat menentukan endianness dengan argumen kedua saat menangani data 16, 32, atau 64 bit. Dalam praktiknya, yang paling aman adalah selalu menentukan endianness sesuai dengan spesifikasi data.

Contoh berikut menunjukkan cara menulis integer 32-bit dan angka floating-point 32-bit dalam format little endian ke sebuah buffer lalu membacanya kembali dengan format yang sama.

 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)
  • Dengan secara eksplisit menentukan endianness, Anda dapat memastikan kompatibilitas dengan berbagai platform dan spesifikasi biner.

Tentang Endianness (Urutan Byte)

Beberapa protokol, seperti yang digunakan dalam jaringan komputer, menggunakan big-endian, sedangkan banyak CPU dan format file umumnya menggunakan desain little-endian. Di DataView, jika argumen kedua diatur ke true, data dianggap sebagai little endian; jika diatur ke false atau diabaikan, dianggap sebagai big endian.

Pada contoh berikut, Anda dapat melihat bagaimana array byte di memori berubah saat menulis angka yang sama menggunakan format big-endian dan little-endian.

 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]
  • Memahami bagaimana urutan byte berubah antara big endian dan little endian akan memudahkan analisis data komunikasi atau format biner.

Input/Output String (Menggunakan TextEncoder dan Decoder Bersama-sama)

DataView sangat baik untuk membaca dan menulis angka, tetapi tidak menangani string secara langsung. Umumnya, string dikodekan menggunakan TextEncoder atau TextDecoder (misalnya ke UTF-8), lalu disalin ke buffer melalui Uint8Array. Berikut adalah contoh menulis string UTF-8 ke buffer dan kemudian membacanya kembali.

 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);
  • Dengan mengonversi string ke biner dan, bila perlu, menambahkan panjangnya di depan, Anda dapat menyimpan string dengan panjang variabel.

Contoh Praktis: Encoding/Decoding Format Biner Kustom

Di bawah ini, kami mendefinisikan format pesan sederhana yang berisi nomor versi, ID, dan nama. Kami mengimplementasikan proses encoding untuk mengubah pesan menjadi data biner, dan proses decoding untuk mengembalikan objek asli dari data biner tersebut. Dalam format pesan ini, byte pertama menyimpan versi, 4 byte berikutnya menyimpan ID dalam format little-endian, byte berikutnya berisi panjang nama, dan terakhir, nama yang disandi dalam UTF-8 disimpan.

 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" }
  • Ini adalah implementasi khas untuk menangani format pesan dasar yang berisi string dengan panjang variabel, dan dapat diterapkan dalam berbagai situasi praktis seperti komunikasi jaringan atau desain file biner kustom.

Perhatian dan Praktik Terbaik

Saat bekerja dengan data biner menggunakan DataView, ada beberapa hal praktis yang perlu diperhatikan selain hanya membaca dan menulis nilai—seperti keamanan, konsistensi penggunaan endianness, dan penanganan tipe data yang tepat. Terutama ketika menangani data biner yang diterima dari sumber eksternal atau menangani integer besar, penting untuk merancang kode supaya mencegah pembacaan yang salah dan buffer overrun. Berikut ini beberapa poin penting yang berguna untuk diingat dalam penggunaan praktis.

  • Pemeriksaan Batas DataView akan melemparkan pengecualian jika offset atau ukuran melebihi batas buffer. Selalu periksa panjang data saat menangani data biner yang tidak tepercaya.

  • Selalu Tentukan Endianness Selalu tentukan secara eksplisit dan konsisten penggunaan little endian atau big endian dalam kode Anda.

  • Konsistensi Tipe Angka pada JavaScript adalah nilai floating-point 64-bit IEEE-754. Metode seperti getUint32 dapat digunakan dengan tepat, tetapi tidak ada getUint64, sehingga diperlukan penanganan khusus untuk integer 64-bit.

  • Penanganan Integer 64-bit Untuk menangani integer 64-bit, Anda perlu menggunakan BigInt atau membagi nilai tersebut secara manual menjadi bagian tingkatan 32-bit atas dan bawah. Berikut adalah contoh sederhana pembacaan integer 64-bit unsigned.

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}
  • Dengan menggunakan BigInt, Anda dapat menangani integer yang lebih besar dari 64-bit dengan aman.

Penggunaan di Node.js (Interoperasi dengan Buffer)

Meskipun Buffer umumnya digunakan di Node.js, sangat mudah juga untuk melakukan konversi antara ArrayBuffer dan DataView. Gunakan properti buffer pada objek Buffer atau konstruktor Uint8Array untuk konversi.

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));
  • Ini dapat digunakan sebagai alat untuk bertukar data biner antara Node.js dan browser.

Ringkasan

DataView adalah mekanisme yang kuat untuk membaca dan menulis data biner secara bebas—sangat berguna dalam situasi di mana kontrol fleksibel seperti penentuan endianness dan akses ke posisi tertentu diperlukan. Dengan menggabungkan ArrayBuffer, TypedArray, dan DataView, Anda dapat secara fleksibel dan akurat menangani data biner dengan TypeScript, sehingga memungkinkan berbagai kasus penggunaan mulai dari implementasi protokol hingga analisis file. Dengan juga memasukkan pengkodean string dan penanganan integer 64-bit sesuai kebutuhan, Anda dapat mencapai operasi biner yang lebih praktis lagi.

Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.

YouTube Video