Chapter sebelumnya memperlihatkan Buffer sebagai array byte, tetapi kita masih memperlakukan konversi dari string seperti kotak hitam. Padahal setiap konversi mengikuti aturan encoding: sekumpulan kaidah yang menentukan karakter mana menjadi byte mana, dan sebaliknya. Salah memilih encoding membuat teks rusak diam-diam — data terbaca, tetapi isinya keliru. Chapter ini membahas encoding yang didukung Node.js, cara menghitung ukuran byte dengan tepat, serta cara menulis data ke posisi tertentu di dalam Buffer.
Encoding Menentukan Bentuk Byte #
Encoding adalah kesepakatan dua arah: Buffer.from() memakainya saat mengubah string menjadi byte, dan buf.toString() memakainya saat mengubah byte kembali menjadi string. Daftar lengkap encoding yang didukung Node.js tercantum pada Buffers and character encodings
. Contoh berikut melakukan perjalanan bolak-balik dari string ke byte lalu pulang lagi:
import { Buffer } from "node:buffer";
const teks = "Halo, Dunia!";
const byte = Buffer.from(teks, "utf8");
console.log("string :", teks);
console.log("hex :", byte.toString("hex"));
console.log("base64 :", byte.toString("base64"));
const dikodekan = byte.toString("base64");
const kembali = Buffer.from(dikodekan, "base64");
console.log("decode :", kembali.toString("utf8"));
console.log("sama? :", kembali.equals(byte));Output yang Dihasilkan:
string : Halo, Dunia!
hex : 48616c6f2c2044756e696121
base64 : SGFsbywgRHVuaWEh
decode : Halo, Dunia!
sama? : trueMari kita telaah baris-baris kode di atas:
- Baris 4 (
Buffer.from(teks, "utf8")): argumen kedua menentukan encoding konversi. Tanpa argumen tersebut,"utf8"tetap menjadi nilai bawaan. - Baris 7-8 (
byte.toString("hex")dantoString("base64")): byte yang sama ditampilkan dalam dua bentuk berbeda. Encodinghexmemakai dua karakter per byte sehingga mudah dibaca manusia, sedangkanbase64memadatkan 3 byte menjadi 4 karakter ASCII. - Baris 10-11: string base64 dikonversi kembali menjadi Buffer dengan
Buffer.from(dikodekan, "base64")— encoding yang sama harus dipakai pada kedua arah agar data utuh. - Baris 14 (
kembali.equals(byte)): methodequals()membandingkan isi dua Buffer byte demi byte. Hasiltruemembuktikan proses pulang-pergi tidak mengubah data. PerilakutoString()dengan seluruh opsinya dirinci pada dokumentasibuf.toString().
Node.js mendukung sejumlah encoding resmi. Tabel berikut merangkum yang paling sering kita jumpai:
| Encoding | Ukuran per karakter | Kegunaan umum |
|---|---|---|
utf8 | 1-4 byte | Standar web dan nilai bawaan Node.js untuk teks |
utf16le | 2-4 byte | Format internal string JavaScript dan API Windows |
latin1 | Selalu 1 byte | Sistem barat lawas; alias binary |
ascii | 1 byte (7 bit) | Teks bahasa Inggris murni; byte di atas 127 dihilangkan |
base64 | 4 karakter per 3 byte | Membawa data biner di media teks seperti email dan data URI |
base64url | Sama dengan base64 | Varian URL-safe tanpa karakter + dan / |
hex | 2 karakter per byte | Menampilkan hash, debug data biner |
Ukuran Karakter Bukan Ukuran Byte #
Properti length pada string menghitung unit kode UTF-16, sedangkan length pada Buffer menghitung byte. Keduanya hanya sama untuk teks ASCII murni. Untuk teks lain, gunakan Buffer.byteLength()
guna mengetahui kebutuhan byte yang sebenarnya:
import { Buffer } from "node:buffer";
const kata = "café";
const aksara = "中";
console.log("'café' : karakter =", kata.length, "| byte =", Buffer.byteLength(kata));
console.log("'中' : karakter =", aksara.length, "| byte =", Buffer.byteLength(aksara));
console.log("hex '中' :", Buffer.from(aksara).toString("hex"));
console.log("hex 'café' :", Buffer.from(kata).toString("hex"));Output yang Dihasilkan:
'café' : karakter = 4 | byte = 5
'中' : karakter = 1 | byte = 3
hex '中' : e4b8ad
hex 'café' : 636166c3a9Kata "café" terdiri atas 4 karakter tetapi memakan 5 byte, karena huruf é dikodekan UTF-8 sebagai dua byte c3 a9. Aksara "中" lebih ekstrem lagi: 1 karakter menjadi 3 byte e4 b8 ad. Perbedaan ini bukan sekadar trivia — saat mengalokasikan Buffer atau memotong data biner, yang kita hitung adalah byte, bukan karakter.
Menulis pada Posisi Tertentu #
Method buf.write(string, offset, length)
menyalin byte dari string ke dalam Buffer mulai posisi offset, sebanyak maksimum length byte, lalu mengembalikan jumlah byte yang benar-benar tersalin:
import { Buffer } from "node:buffer";
const buf = Buffer.alloc(6);
buf.write("ab", 0);
buf.write("cd", 2);
buf.write("ef", 4);
console.log("isi awal :", buf.toString());
const byteDitulis = buf.write("XYZ", 1, 3);
console.log("byte yang ditulis:", byteDitulis);
console.log("isi akhir:", buf.toString());Output yang Dihasilkan:
isi awal : abcdef
byte yang ditulis: 3
isi akhir: aXYZefTiga panggilan write() pertama mengisi byte 0-1, 2-3, dan 4-5 sehingga Buffer berisi abcdef. Panggilan keempat menulis mulai offset 1 dengan batas 3 byte: hanya "XYZ" yang muat, hasilnya aXYZef, dan nilai baliknya 3. Nilai balik ini penting ketika ruang Buffer lebih sempit daripada string — sisa string yang tidak tertampung harus ditangani, misalnya ditulis pada iterasi berikutnya.
Ketika Encoding Tidak Cocok #
Data tidak selalu rusak secara kasat mata. Ketika byte UTF-8 dibaca dengan encoding lain, kita tetap mendapatkan string — hanya saja isinya keliru:
import { Buffer } from "node:buffer";
const asli = "héllo";
const byteUtf8 = Buffer.from(asli, "utf8");
console.log("asli :", asli);
console.log("hex (utf8) :", byteUtf8.toString("hex"));
console.log("dibaca latin1 :", byteUtf8.toString("latin1"));
console.log("dibaca utf8 :", byteUtf8.toString("utf8"));Output yang Dihasilkan:
asli : héllo
hex (utf8) : 68c3a96c6c6f
dibaca latin1 : héllo
dibaca utf8 : hélloDua byte c3 a9 untuk huruf é dibaca latin1 sebagai dua karakter terpisah à dan ©, menghasilkan héllo. Jenis kerusakan ini sering muncul ketika membaca berkas lama, data dari sistem lain, atau respons jaringan tanpa encoding yang jelas. Pembacaan dengan encoding yang benar mengembalikan teks asli tanpa masalah.
Dengan Buffer dan encoding sebagai fondasi, kita kini bisa menyimpan dan mengubah data biner secara presisi. Pertanyaan berikutnya menyangkut skala: bagaimana memproses berkas berukuran besar atau data jaringan yang datang bertahap tanpa memuat semuanya ke memori sekaligus? Jawabannya adalah stream, yang kita mulai dari konsep dasarnya pada Chapter Konsep Stream.