Buffer — alloc, from, concat, encoding

~15 daq · Node.js · Stream va Buffer

Muammodan boshlaylik

Stream darslarida chunk — bo'lak haqida gapirdik. Encoding bermagan holda readFile <Buffer 53 61 6c 6f 6d> qaytaradi. Bu nima?

Kompyuter ma'lumotni faqat baytlar sifatida saqlaydi. 'Salom' matni ham, rasm ham, video ham — barchasi baytlar. JavaScript da esa string, number, object bor — lekin xom baytlar bilan ishlash uchun maxsus tur yo'q edi.

Node.js Buffer ni aynan shu uchun yaratdi — xom baytlar bilan ishlash uchun.


Buffer nima?

Buffer — xotiradagi qat'iy hajmli baytlar to'plami. Yaratilgandan keyin hajmi o'zgarmaydi.

Nima uchun kerak? Fayl o'qish, tarmoq ma'lumoti, kriptografiya — bularning hammasi baytlar bilan ishlaydi. String esa Unicode — baytlar emas. Shuning uchun ikki dunyo o'rtasida ko'prik kerak. Buffer — o'sha ko'prik.

Disk/Tarmoq → [baytlar] → Buffer → toString() → String
String → Buffer.from() → [baytlar] → Disk/Tarmoq

Buffer.from — mavjud ma'lumotdan Buffer yaratish

// Stringdan:
const buf = Buffer.from('Salom');
console.log(buf);
// <Buffer 53 61 6c 6f 6d>  ← har harf baytga aylandi

console.log(buf.length); // 5  ← 5 bayt

// Encoding ko'rsatish (standart: utf8):
const buf2 = Buffer.from('Salom', 'utf8');
const buf3 = Buffer.from('53616c6f6d', 'hex'); // hex dan
const buf4 = Buffer.from('U2Fsb20=', 'base64'); // base64 dan

Massivdan:

const buf = Buffer.from([0x53, 0x61, 0x6c, 0x6f, 0x6d]);
console.log(buf.toString()); // 'Salom'

Buffer.alloc — bo'sh Buffer yaratish

Buffer.alloc — berilgan hajmda bo'sh (nollar bilan to'ldirilgan) Buffer yaratadi.

const buf = Buffer.alloc(10);
console.log(buf);
// <Buffer 00 00 00 00 00 00 00 00 00 00>  ← 10 ta nol

// Boshlang'ich qiymat bilan:
const buf2 = Buffer.alloc(5, 0xff);
console.log(buf2);
// <Buffer ff ff ff ff ff>

Nima uchun alloc? Protokollar bilan ishlashda — masalan, TCP paket yaratishda — qat'iy hajmli xotira kerak bo'ladi.

⚠️ Buffer.allocUnsafe(n) ham bor — tezroq, lekin xotira tozalanmaydi (eski ma'lumot bo'lishi mumkin). Xavfsizlik muhim bo'lsa — alloc ishlatiladi.


Buffer ni o'qish va yozish

const buf = Buffer.alloc(4);

// Yozish:
buf.writeUInt8(255, 0);   // 0-pozitsiyaga 255 yoz
buf.writeUInt8(128, 1);   // 1-pozitsiyaga 128 yoz
buf.writeUInt16BE(1000, 2); // 2-3 pozitsiyaga 1000 yoz (Big Endian)

console.log(buf);
// <Buffer ff 80 03 e8>

// O'qish:
console.log(buf.readUInt8(0));    // 255
console.log(buf.readUInt8(1));    // 128
console.log(buf.readUInt16BE(2)); // 1000

Bu past darajali operatsiyalar — odatda protokollar (TCP, UDP, binary fayl formatlari) bilan ishlashda kerak bo'ladi.


toString — Buffer ni stringga aylantirish

const buf = Buffer.from('Salom, dunyo!');

buf.toString();          // 'Salom, dunyo!'  ← standart utf8
buf.toString('utf8');    // 'Salom, dunyo!'
buf.toString('hex');     // '53616c6f6d2c2064756e796f21'
buf.toString('base64');  // 'U2Fsb20sIGR1bnlvIQ=='

// Qism:
buf.toString('utf8', 0, 5); // 'Salom'  ← 0 dan 5 gacha

Buffer.concat — bir nechta Buffer ni birlashtirish

Stream dan kelgan bo'laklarni birlashtirish uchun ko'p ishlatiladi:

const chunks = [];

readStream.on('data', (chunk) => {
  chunks.push(chunk);
});

readStream.on('end', () => {
  const fullBuffer = Buffer.concat(chunks);
  console.log(fullBuffer.toString());
});

Nima uchun + bilan birlashtirmaslik kerak?

// Xato — Buffer + Buffer = string emas:
const result = chunk1 + chunk2;
// '[object Object][object Object]'  ← noto'g'ri

// To'g'ri:
const result = Buffer.concat([chunk1, chunk2]);

Hajmni oldindan bilsangiz — tezroq:

const total = chunks.reduce((sum, c) => sum + c.length, 0);
const result = Buffer.concat(chunks, total);

Buffer va String — encoding

Encoding — baytlarni qanday matnга aylantirish qoidasi. Bir xil baytlar turli encoding da turli matn beradi.

const buf = Buffer.from([0xd1, 0x81, 0xd0, 0xb0, 0xd0, 0xbb, 0xd0, 0xbe, 0xd0, 0xbc]);

buf.toString('utf8');    // 'салом'  ← to'g'ri (kirill)
buf.toString('latin1');  // 'Ñ\x81алом'  ← noto'g'ri encoding

Node.js qo'llab-quvvatlaydigan asosiy encodinglar:

Encoding Nima uchun
utf8 Standart, matn uchun
hex Kriptografiya, debug
base64 Email, URL, JSON ichida binary
base64url URL xavfsiz base64 (token uchun)
latin1 Eski tizimlar
binary latin1 bilan bir xil

Amaliy misol — binary protokol

Ba'zi protokollar (masalan, game server, IoT qurilmalar) ma'lumotni binary formatda yuboradi. Buffer bilan ishlash:

// Protokol: [1 bayt tip] [4 bayt uzunlik] [N bayt ma'lumot]
function createPacket(type, data) {
  const dataBuffer = Buffer.from(data, 'utf8');
  const packet     = Buffer.alloc(1 + 4 + dataBuffer.length);

  packet.writeUInt8(type, 0);              // tip
  packet.writeUInt32BE(dataBuffer.length, 1); // uzunlik
  dataBuffer.copy(packet, 5);              // ma'lumot

  return packet;
}

function parsePacket(packet) {
  const type   = packet.readUInt8(0);
  const length = packet.readUInt32BE(1);
  const data   = packet.slice(5, 5 + length).toString('utf8');
  return { type, data };
}

const packet = createPacket(1, 'Salom');
console.log(parsePacket(packet));
// { type: 1, data: 'Salom' }

Tez-tez uchraydigan xatolar

new Buffer() ishlatish (deprecated):

// Xato — eskirgan, xavfli:
const buf = new Buffer('Salom');

// To'g'ri:
const buf = Buffer.from('Salom');

Buffer uzunligi va string uzunligi farqi:

const str = 'Привет'; // kirill harflari
console.log(str.length);              // 6  ← belgilar soni
console.log(Buffer.from(str).length); // 12 ← baytlar soni (har kirill = 2 bayt)

UTF-8 da lotin harflari 1 bayt, kirill/arab/xitoy harflari 2-4 bayt. string.length belgilar sonini beradi, Buffer.length baytlar sonini.

Encoding ko'rsatmaslik:

const buf = Buffer.from('Salom');
buf.toString(); // 'Salom'  ← utf8 standart, ishlaydi

// Lekin hex string uchun:
const hexBuf = Buffer.from('53616c6f6d'); // bu string sifatida qabul qilinadi!
hexBuf.toString(); // '53616c6f6d'  ← noto'g'ri

// To'g'ri:
const hexBuf = Buffer.from('53616c6f6d', 'hex');
hexBuf.toString(); // 'Salom'

Xulosa

Buffer — Node.js da xom baytlar bilan ishlash uchun. Fayl, tarmoq, kriptografiya — bularning hammasi baytlar bilan ishlaydi, Buffer esa JavaScript va baytlar o'rtasidagi ko'prik.

Kundalik ishda ko'pincha Buffer.from(), buf.toString(), Buffer.concat() ishlatiladi. Past darajali protokollar bilan ishlashda readUInt8, writeUInt32BE kabi metodlar kerak bo'ladi.


Keyingi dars

20-dars: process — argv, env, exit, uncaughtException, SIGINT