Ikkilik ma'lumot va fayllar

File va FileReader

Foydalanuvchi kompyuteridagi faylni brauzerga yuklaganida (masalan <input type="file"> orqali), biz File obyektini olamiz. File โ€” bu Blobning kengaytirilgan ko'rinishi bo'lib, unga fayl nomi va o'zgartirilgan sanasi qo'shilgan. Fayl mazmunini o'qish uchun esa FileReader ishlatiladi. Bularning barchasi brauzerga xos, shuning uchun quyidagi misollar brauzer muhitiga oid.

File obyekti

File โ€” Blobdan meros oladi, shuning uchun uning barcha xususiyatlari (size, type, slice) mavjud, plyus qo'shimchalari:

File obyektini konstruktor orqali ham yasash mumkin, lekin amaliyotda ko'proq foydalanuvchi tanlovi orqali olinadi:

// File ni to'g'ridan-to'g'ri yaratish (kam ishlatiladi)
let file = new File(["salom"], "hello.txt", {
  type: "text/plain",
  lastModified: Date.now()
});

console.log(file.name);         // hello.txt
console.log(file.size);         // 5
console.log(file.type);         // text/plain

input.files orqali fayl olish

Amaliyotda File obyektlari <input type="file"> elementidan olinadi. Foydalanuvchi fayl tanlagach, input.files โ€” FileList (fayllar ro'yxati) to'ldiriladi:

// HTML: <input type="file" id="tanlov" multiple>

let input = document.getElementById("tanlov");

input.addEventListener("change", function() {
  let files = input.files; // FileList

  console.log("Tanlangan fayllar: " + files.length);

  for (let file of files) {
    console.log(file.name + " - " + file.size + " bayt");
  }
});
multiple atributi bir nechta fayl tanlashga imkon beradi. files โ€” FileList obyekti, u massivga o'xshaydi (indeks va length bor), lekin toza massiv emas. Kerak bo'lsa Array.from(files) bilan massivga o'giring.
Fayllarni tortib tashlash (drag and drop) orqali ham olish mumkin: drop hodisasida event.dataTransfer.files ham FileList qaytaradi โ€” xuddi input.filesdek ishlaydi.

FileReader: faylni o'qish

File (yoki Blob) mazmunini o'qish uchun FileReader ishlatiladi. Bu โ€” asinxron obyekt bo'lib, faylni o'qib bo'lgach hodisa (event) chaqiradi:

let reader = new FileReader();

FileReaderning o'qish metodlari fayl mazmunini turli formatda beradi:

O'qish asinxron bo'lgani uchun natija to'g'ridan-to'g'ri qaytarilmaydi โ€” u hodisalar orqali keladi:

readAsText: matnli faylni o'qish

Matnli faylni o'qishning to'liq misoli:

let input = document.getElementById("tanlov");

input.addEventListener("change", function() {
  let file = input.files[0];
  let reader = new FileReader();

  reader.onload = function() {
    // o'qish tugadi, natija reader.result da
    console.log(reader.result);
  };

  reader.onerror = function() {
    console.log("Xatolik: " + reader.error);
  };

  reader.readAsText(file); // o'qishni boshlaymiz
});
readAsText (va boshqa readAs...) metodlari darhol natija qaytarmaydi. Ular o'qishni boshlaydi va tugagach onloadni chaqiradi. Natijaga onload ichida murojaat qiling โ€” readAsText chaqiruvidan keyin darhol reader.result hali null bo'ladi.

readAsDataURL: rasmni ko'rsatish

readAsDataURL faylni data: URL (base64) ko'rinishida beradi. Bu, ayniqsa, tanlangan rasmni yuklashdan oldin oldindan ko'rsatish (preview) uchun qulay:

let input = document.getElementById("rasmTanlov");

input.addEventListener("change", function() {
  let file = input.files[0];
  let reader = new FileReader();

  reader.onload = function() {
    // natija: data:image/png;base64,iVBORw0KGgo...
    let img = document.createElement("img");
    img.src = reader.result;
    document.body.appendChild(img);
  };

  reader.readAsDataURL(file);
});
data: URL rasmni to'liq base64 satr sifatida saqlaydi โ€” serverga murojaat qilmaydi. Kichik rasmlar uchun qulay, lekin base64 ma'lumot hajmini ~33% oshiradi. Katta fayllar uchun URL.createObjectURL(file) tejamkorroq (u ham to'g'ridan-to'g'ri File bilan ishlaydi).

readAsArrayBuffer: ikkilik o'qish

Fayl baytlarini past darajada qayta ishlash kerak bo'lsa (masalan, fayl formatini tahlil qilish, sarlavhani o'qish), readAsArrayBuffer ishlatiladi:

let file = input.files[0];
let reader = new FileReader();

reader.onload = function() {
  let buffer = reader.result;      // ArrayBuffer
  let bytes = new Uint8Array(buffer);

  // masalan, PNG sarlavhasini tekshiramiz
  // PNG fayllari 0x89 0x50 0x4E 0x47 bilan boshlanadi
  let isPng = bytes[0] === 0x89 &&
              bytes[1] === 0x50 &&
              bytes[2] === 0x4E &&
              bytes[3] === 0x47;

  console.log("PNG fayli: " + isPng);
};

reader.readAsArrayBuffer(file);
Katta faylning faqat bir qismini o'qish kerak bo'lsa, avval file.slice(0, 100) bilan bo'lak oling, so'ng shu Blobni readAsArrayBufferga bering. Butun faylni o'qish shart emas โ€” bu tezroq va xotira tejaydi.

Yuklash jarayonini kuzatish (progress)

Katta faylni o'qiganda foydalanuvchiga jarayon foizini ko'rsatish uchun progress hodisasi ishlatiladi. Uning obyektida loaded (o'qilgan baytlar) va total (jami baytlar) bor:

let reader = new FileReader();

reader.onprogress = function(event) {
  if (event.lengthComputable) {
    let foiz = Math.round((event.loaded / event.total) * 100);
    console.log("O'qildi: " + foiz + "%");
  }
};

reader.onload = function() {
  console.log("Tugadi!");
};

reader.readAsArrayBuffer(file);
event.lengthComputable โ€” jami hajm oldindan ma'lummi degan bayroq. Agar u false bo'lsa, foizni hisoblab bo'lmaydi (total noaniq). Lokal fayllar uchun odatda true bo'ladi.

O'qishni to'xtatish

Boshlangan o'qishni reader.abort() bilan bekor qilish mumkin. Bu, masalan, foydalanuvchi katta faylni tanlab, so'ng fikridan qaytganda kerak bo'ladi:

let reader = new FileReader();
reader.readAsArrayBuffer(katta_fayl);

// keyinroq, kerak bo'lmay qolsa:
reader.abort(); // o'qishni to'xtatamiz

reader.onabort = function() {
  console.log("O'qish bekor qilindi");
};

FileReader va Blob

FileReader nafaqat File, balki har qanday Blobni o'qiy oladi โ€” chunki File Blobdan meros oladi. Shuning uchun fetchdan kelgan Blobni ham FileReader bilan o'qish mumkin. Lekin zamonaviy kodda Blobning o'z await blob.text() / await blob.arrayBuffer() metodlari qulayroq โ€” ular Promise qaytaradi va async/await bilan toza yoziladi.

Yangi kodda faylni o'qish uchun ko'pincha await file.text() yoki await file.arrayBuffer() yetarli โ€” FileReader shart emas. FileReader esa progress hodisasi kerak bo'lganda yoki eski brauzerlarni qo'llab-quvvatlashda foydali bo'lib qoladi.

Xulosa