داده‌های دودویی (Binary Data)

ArrayBuffer و SharedArrayBuffer، TypedArray انواع آن، DataView، Blob و File و FileReader، TextEncoder و TextDecoder و کار با داده باینری.

داده دودویی چیست؟

رشته‌ها برای متن هستند اما برای فایل، تصویر، صدا و شبکه به بایت‌های خام نیاز داریم:

رشته: "سلام"  ← کاراکترها
دودویی: 0xD8 0xA9 0xD9... ← بایت‌ها

// جاوا اسکریپت ساختارهای باینری:
ArrayBuffer → حافظه خام
TypedArray → دید عددی روی آن
DataView → خواندن/نوشتن کنترل‌شده
Blob/File → داده فایل‌مانند

ArrayBuffer — بافر خام

// ساخت بافر ۱۶ بایتی:
const buffer = new ArrayBuffer(16);

console.log(buffer.byteLength);  // 16

// مستقیم قابل دسترسی نیست — نیاز به View:
const view = new Uint8Array(buffer);
view[0] = 255;
view[1] = 0x80;    // هگزادسیمال

console.log(view[0]); // 255
console.log(view[1]); // 128
ArrayBuffer فقط حافظه است — بدون متد، بدون نوع. با TypedArray یا DataView آن را می‌خوانیم.

TypedArray — آرایه نوع‌دار

// انواع بر اساس اندازه و علامت:
// Int8    — ۱ بایت علامت‌دار (-128 تا 127)
// Uint8   — ۱ بایت بدون علامت (0 تا 255)
// Int16   — ۲ بایت (-32768 تا 32767)
// Uint16  — ۲ بایت (0 تا 65535)
// Int32   — ۴ بایت
// Uint32  — ۴ بایت
// Float32 — ۴ بایت اعشاری
// Float64 — ۸ بایت
// BigInt64 — ۸ بایت BigInt

// ساخت مستقیم:
const bytes = new Uint8Array([10, 20, 30]);
console.log(bytes.length);     // 3
console.log(bytes[0]);         // 10

// سرریز — مقدار wrap می‌شود:
bytes[0] = 300;                // بیش از 255!
console.log(bytes[0]);         // 44 — 300 % 256

// Int8 با علامت:
const signed = new Int8Array([127, -128]);
signed[0] = 128;               // بیش از حد!
console.log(signed[0]);        // -128

پیمایش و متدهای TypedArray

const data = new Uint8Array([5, 10, 15, 20, 25]);

// مثل آرایه:
console.log(data.length);       // 5
console.log(data.indexOf(15));  // 2

data.forEach(v => console.log(v));

const doubled = data.map(v => v * 2);
console.log(doubled);  // [10, 20, 30, 40, 50]

const filtered = data.filter(v => v > 10);
console.log(filtered); // [15, 20, 25]

const sum = data.reduce((a, b) => a + b, 0);
console.log(sum);      // 75

// subarray — view بدون کپی:
const part = data.subarray(1, 3);
console.log(part);     // [10, 15] — همان حافظه!

// copy — کپی واقعی:
const copy = data.slice(1, 3);
console.log(copy);     // [10, 15] — جدید

// set — جایگذاری:
const target = new Uint8Array(5);
target.set([1, 2, 3], 1);  // از ایندکس 1
console.log(target);   // [0, 1, 2, 3, 0]

DataView — خواندن دقیق

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

// نوشتن در offset مشخص:
view.setInt16(0, 12345);       // ۲ بایت در ابتدا
view.setFloat64(2, 3.14159);   // ۸ بایت... 

// صبر — همپوشانی! مراقب offset:
const buf2 = new ArrayBuffer(16);
const v2 = new DataView(buf2);
v2.setInt16(0, 1000);          // بایت 0-1
v2.setInt16(2, 2000);          // بایت 2-3
v2.setFloat64(4, 2.718);       // بایت 4-11

// خواندن:
console.log(v2.getInt16(0));    // 1000
console.log(v2.getInt16(2));    // 2000
console.log(v2.getFloat64(4));  // 2.718

// Endianness — ترتیب بایت:
v2.setInt16(0, 0x1234, false);  // big-endian
v2.setInt16(2, 0x1234, true);   // little-endian
console.log(v2.getInt16(0, false).toString(16)); // 1234
console.log(v2.getInt16(2, false).toString(16)); // 3412 — برعکس!

Blob — داده فایل‌مانند

// ساخت:
const blob = new Blob(["متن", " بیشتر"], { type: "text/plain" });

console.log(blob.size);  // 15 — بایت
console.log(blob.type);  // "text/plain"

// slice — برش:
const part = blob.slice(0, 5, "text/plain");

// چند blob یکی:
const combined = new Blob([blob, new Blob(["آخر"])]);
console.log(combined.size);

// خواندن:
const text = await blob.text();
const buffer = await blob.arrayBuffer();

File — فایل واقعی

// از input:
const fileInput = document.querySelector('input[type=file]');
fileInput.addEventListener("change", (e) => {
    const file = e.target.files[0];

    console.log(file.name);       // نام
    console.log(file.size);       // حجم بایت
    console.log(file.type);       // MIME
    console.log(file.lastModified); // timestamp
});

// ساخت دستی:
const file = new File(["محتوا"], "note.txt", {
    type: "text/plain",
    lastModified: Date.now()
});

// File از Blob ارث می‌برد — همه متدها + name و lastModified

FileReader — خواندن فایل

const reader = new FileReader();

reader.onload = (e) => {
    console.log("نتیجه:", e.target.result);
};
reader.onerror = () => console.log("خطا!");
reader.onprogress = (e) => {
    console.log((e.loaded / e.total * 100) + "%");
};

// روش‌های خواندن:
reader.readAsText(file);           // متن
reader.readAsArrayBuffer(file);    // بایت‌ها  
reader.readAsDataURL(file);        // base64 — برای img

FileReader با Promise

function readFile(file, as = "text") {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = reject;
        reader["readAs" + as](file);
    });
}

// استفاده:
const text = await readFile(file, "Text");
const dataUrl = await readFile(imageFile, "DataURL");

// نمایش تصویر:
const img = document.querySelector("img");
img.src = await readFile(file, "DataURL");

TextEncoder و TextDecoder

// متن → بایت:
const encoder = new TextEncoder();
const bytes = encoder.encode("سلام");
console.log(bytes);  // Uint8Array(8) [216, 169, 217, ...]
// هر حرف فارسی ۲ بایت UTF-8

// بایت → متن:
const decoder = new TextDecoder("utf-8");
const text = decoder.decode(bytes);
console.log(text);   // "سلام"

// انکودینگ‌های دیگر:
const winDecoder = new TextDecoder("windows-1256");  // عربی/فارسی قدیمی
const utf16 = new TextDecoder("utf-16le");

تبدیل‌های کاربردی

// رشته → Base64:
function toBase64(str) {
    const bytes = new TextEncoder().encode(str);
    let binary = "";
    bytes.forEach(b => binary += String.fromCharCode(b));
    return btoa(binary);
}

console.log(toBase64("سلام")); // 2LPZitiv

// Base64 → رشته:
function fromBase64(b64) {
    const binary = atob(b64);
    const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
    return new TextDecoder().decode(bytes);
}

console.log(fromBase64("2LPZitiv")); // سلام

// عدد ↔ بایت:
const num = 123456;
const b = new Uint8Array(4);
new DataView(b.buffer).setUint32(0, num);
console.log(b); // [0, 1, 226, 64]
console.log(new DataView(b.buffer).getUint32(0)); // 123456

هگزادسیمال

// بایت → هگز:
const bytes = new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF]);
const hex = [...bytes].map(b => b.toString(16).padStart(2, "0")).join(" ");
console.log(hex); // "de ad be ef"

// هگز → بایت:
const hexStr = "deadbeef";
const fromHex = new Uint8Array(
    hexStr.match(/.{2}/g).map(h => parseInt(h, 16))
);
console.log(fromHex); // [222, 173, 190, 239]

SharedArrayBuffer و Atomics

// حافظه مشترک بین Workerها:
const shared = new SharedArrayBuffer(4);
const view = new Int32Array(shared);

// در Worker:
// Atomics.store(view, 0, 42);  — اتمیک

// اصلی:
Atomics.store(view, 0, 42);
console.log(Atomics.load(view, 0)); // 42

// عملیات اتمیک — بدون Race Condition:
Atomics.add(view, 0, 10);
console.log(Atomics.load(view, 0)); // 52

// انتظار و اطلاع:
// Worker: Atomics.wait(view, 0, 0);       — منتظر
// Main:   Atomics.notify(view, 0);        — بیدار کن

جمع‌بندی

ساختارکاربرد
ArrayBufferحافظه خام بایت
Uint8Arrayبایت‌های ساده — رایج‌ترین
DataViewخواندن چند نوع با Endianness
Blobداده فایل‌مانند
Fileفایل واقعی با نام
TextEncoderمتن → بایت

این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.

ابزارهای مرتبط