Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Tanlangan fayl: <input type="file"> dan File gacha
- 2.1 input.files
- 2.2 FileList — massiv emas
- 2.3 type — kengaytmadan taxmin
- 3. Blob: baytlar qutisi
- 3.1 Blob nima
- 3.2 size — belgilarda emas, baytlarda
- 3.3 Qismlardan yig'ish
- 3.4 slice(): bo'lak kesish
- 4. Obyekt URL: Blob'ga manzil berish
- 4.1 URL.createObjectURL()
- 4.2 «Bahor»: menyu belgisi xotiradan
- 4.3 revokeObjectURL: xotirani qaytarish
- 5. Yuklab berish: <a download>
- 5.1 download atributi
- 5.2 «Bahor»: menyuni CSV qilib yuklab olish
- 5.3 Obyekt URL yoki data: URL
- 6. Hujumchi nigohi
- 7. Ko'p uchraydigan xatolar
- 7.1 FileList ni massiv deb o'ylash
- 7.2 Hajmni belgilarda hisoblash
- 7.3 revokeObjectURL ni unutish
- 7.4 Juda erta revoke
- 7.5 Boshqa saytdagi faylga download
- 8. Mashqlar
- 1-mashq (oson): Matn fayl
- 2-mashq (o'rta): Bronlar JSON fayli
- 3-mashq (qiyin): Rasmlar galereyasi
- 4-mashq: Vazifalar qadami — eksport faylga
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript File va Blob: faylni yaratish, ko'rsatish va yuklab berish
Qisqacha:
Blob— brauzer xotirasidagi baytlar bo'lagi, unda hajm (size) va tur (type) bor. Fayl obyekti (File) — nomi va o'zgartirilgan sanasi qo'shilganBlob; uni<input type="file">beradi yokinew File()bilan o'zingiz yaratasiz.URL.createObjectURL(blob)bo'lakka vaqtinchalikblob:manzil beradi — uni<img src>ga qo'yib ko'rsatasiz yoki<a download>bilan fayl qilib yuklab berasiz. Ish tugagach manzilURL.revokeObjectURL()bilan bo'shatiladi.
Bu darsda
<input type="file">dan tanlangan fayllarni olib,name,size,type,lastModifiedni o'qiy olasiz.new Blob()vanew File()bilan xotirada fayl yarata olasiz,slice()bilan bo'lak kesasiz.URL.createObjectURLbilan faylni sahifada ko'rsatasiz varevokeObjectURLbilan xotirani bo'shatasiz.- Serversiz,
<a download>bilan foydalanuvchiga fayl yuklab bera olasiz. vazifalarga "Faylga yuklab olish" tugmasini qo'shasiz.
Oldin bilishingiz kerak: Fayl yuklash maydoni, FormData, Typed arrays va binar ma'lumot, Matnli va binar fayllar.
1. Nega bu kerak?
Shu darsdan 13-qismning "fayllar" bloki boshlanadi: to'rt dars ketma-ket. Bugun — fayl nima ekanini va uni qanday yaratishni. Keyingi darslarda — faylni o'qish, serverga yuklash va sudrab tashlash.
«Bahor»da ikki vazifa bor. Birinchisi — Jasur akaning iltimosi. U menyuni Excel'da ochmoqchi: "Saytda bitta tugma bo'lsin, bossam — menyu fayl bo'lib tushsin". Sardorning birinchi fikri — serverda fayl yasash. Lekin menyu allaqachon brauzerda, JavaScript massivida turibdi. Uni serverga yuborib, fayl qilib, qaytarib olish — ortiqcha yo'l.
Ikkinchisi — mehmonlar tomonda. Fayl yuklash maydoni darsida bron formasiga to'lov cheki maydonini qo'shgan edik. Mehmon chekni tanlaydi, lekin nimani tanlaganini ko'rmaydi — faqat fayl nomi. Xato rasm yuborib qo'yishi mumkin.
Ikkala vazifaning kaliti bitta: brauzer fayllar bilan o'zi ishlay oladi. Faylni xotirada yaratish, tanlangan faylni ko'rsatish, uni yuklab berish — serversiz. Bularning hammasi ikki obyekt atrofida qurilgan: Blob va File.
2. Tanlangan fayl: <input type="file"> dan File gacha
2.1 input.files
Fayl yuklash maydoni darsida <input type="file"> ni HTML tomondan ko'rdik. JavaScript'da tanlangan fayllar maydonning files xususiyatida turadi. Foydalanuvchi fayl tanlaganda maydon change hodisasini beradi (input va change darsi).
Fayl tanlang (bir nechtasini ham bo'ladi) — oynada uning ma'lumotlari chiqadi:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
li { margin: 0.25rem 0; }
</style>
<label for="files">Fayl tanlang:</label>
<input type="file" id="files" multiple>
<ul id="info"></ul>
<script>
const input = document.getElementById("files");
const info = document.getElementById("info");
function formatSize(bytes) {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / 1024 ** 2).toFixed(1)} MB`;
}
input.addEventListener("change", () => {
info.replaceChildren();
for (const file of input.files) {
const item = document.createElement("li");
const date = new Date(file.lastModified);
const changed = date.toLocaleString("uz");
item.textContent = `${file.name} — ${formatSize(file.size)},`
+ ` tur: ${file.type || "noma'lum"}, o'zgargan: ${changed}`;
info.append(item);
}
console.log(`${input.files.length} ta fayl tanlandi`);
});
</script>Har faylda to'rtta asosiy xususiyat bor:
| Xususiyat | Nima | Misol |
|---|---|---|
name |
fayl nomi (papkasiz) | "chek.jpg" |
size |
hajmi, baytda | 482133 |
type |
MIME turi | "image/jpeg" |
lastModified |
oxirgi o'zgargan vaqt, ms | 1791201600000 |
formatSize — baytlarni odam o'qiydigan ko'rinishga keltiradi: 1 KB = 1 024 bayt, 1 MB = 1 024 KB (1024 ** 2 — 1 024 ning kvadrati).
Biz ikki fayl tanlab sinadik: 900 000 baytli chek.bin va 11 baytli a.txt. Ro'yxatda chek.bin — 878.9 KB, tur: application/octet-stream va a.txt — 11 B, tur: text/plain chiqdi, konsolda esa 2 ta fayl tanlandi. 900 000 ÷ 1 024 ≈ 878,9 — shuning uchun KB soni "yumaloq" emas.
Ikki muhim narsa:
- Faylning yo'li yo'q.
name— faqat nom. Diskdagi to'liq yo'l (C:\Users\...) sahifaga berilmaydi — bu foydalanuvchining shaxsiy ma'lumoti. - Fayl hech qayerga ketmadi. Hammasi brauzer ichida. Server faqat siz
fetchbilan yuborsangiz ko'radi (keyingi darslarda).
2.2 FileList — massiv emas
input.files — FileList obyekti. U length va for...of ni biladi, lekin massiv emas. map, filter kabi metodlari yo'q:
const names = input.files.map((file) => file.name);Chrome 154 da:
TypeError: input.files.map is not a functionTarjimasi: "input.files.map — funksiya emas". FileList da map degan narsa umuman yo'q, undefined ni chaqirib bo'lmaydi. Tuzatish: avval haqiqiy massivga aylantiring — [...input.files].map(...) yoki Array.from(input.files) (Massivga o'xshash obyektlar darsidagi usullar).
2.3 type — kengaytmadan taxmin
file.type ni fayl ichidan o'qib aniqlanmaydi. Brauzer uni fayl nomining kengaytmasidan taxmin qiladi. virus.exe ni rasm.jpg deb qayta nomlasangiz — type "image/jpeg" bo'ladi. Notanish kengaytmada esa bo'sh satr: "".
Shuning uchun type — faqat foydalanuvchiga qulaylik ("siz rasm tanlamadingiz"). Himoya emas. Faylning haqiqiy turini baytlaridan tekshirishni keyingi darsda ko'ramiz.
Tekshirib ko'ring: Foydalanuvchi
menyu.xlsxfaylini tanladi, lekin uning kompyuterida Excel o'rnatilmagan.file.typenimaga teng bo'lishi mumkin?
Javob
Kengaytma ma'lum bo'lsa — "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", aks holda bo'sh satr "". Natija tizim va brauzerga bog'liq. Shuning uchun type ga to'liq tayanmang: bo'sh bo'lishi mumkinligini hisobga oling.
3. Blob: baytlar qutisi
3.1 Blob nima
Blob (inglizcha "Binary Large OBject" — katta binar obyekt) — baytlar bo'lagi, ustiga ikki yorliq yopishtirilgan: hajmi va turi. Ichidagi baytlarni to'g'ridan-to'g'ri o'qib bo'lmaydi — buning uchun maxsus usullar bor (keyingi darsda).
O'xshatish: Blob — yopiq, tasmalangan pochta qutisi. Ustida "3 kg, ichida: kitob" degan yorliq bor. Qutini boshqa joyga uzatish, ikkiga bo'lish, unga manzil yozish mumkin. Ichiga qarash uchun esa uni ochish kerak.
File — xuddi shu quti, faqat yorlig'ida yana nom va sana bor. File — Blob ning "farzandi": u Blob dan meros oladi (prototip zanjiri darsidagi kabi). Shuning uchun Blob qabul qiladigan har joyga File ni ham berish mumkin.
File va Blob Node 24 da ham bor. Shuning uchun quyidagi misollarni shu yerning o'zida ishga tushira olasiz:
const receipt = new File(["Osh — 35 000 so'm"], "chek.txt", {
type: "text/plain",
lastModified: new Date("2026-10-05T12:00:00Z").getTime(),
});
console.log(receipt.name); // chek.txt
console.log(receipt.size); // 19
console.log(receipt.type); // text/plain
console.log(receipt instanceof Blob); // truenew File(qismlar, nom, sozlamalar) — uch argument: tarkib qismlari ro'yxatda, fayl nomi va { type, lastModified }. lastModified ni bermasangiz — hozirgi vaqt olinadi.
3.2 size — belgilarda emas, baytlarda
"Osh — 35 000 so'm" — 17 belgi. size esa 19. Nega?
Matnli va binar fayllar darsini eslang: matn faylga UTF-8 bilan yoziladi. Lotin harflari va raqamlar 1 baytdan, uzun tire — esa 3 bayt. 16 + 3 = 19. Emoji bilan farq yana ham ko'p:
const label = "Osh 🍚";
console.log(label.length); // 6
console.log(new Blob([label]).size); // 8length UTF-16 birliklarini sanaydi (emoji — 2 ta), size esa UTF-8 baytlarini (emoji — 4 bayt). Hisoblang: O, s, h va bo'sh joy — 4 bayt, emoji — yana 4: jami 8. Server "1 MB gacha" deganda — baytlarni nazarda tutadi. Hajmni doim size bilan tekshiring.
3.3 Qismlardan yig'ish
new Blob(qismlar, { type }) ga turli narsalarni aralash berish mumkin: satrlar, typed array'lar va boshqa Blob'lar. Ular ketma-ket bitta baytlar qatoriga yopishtiriladi:
const greeting = new Blob(
["Bahor", new Uint8Array([32, 79, 75]), new Blob(["!"])],
{ type: "text/plain" },
);
console.log(greeting.size); // 9
console.log(await greeting.text()); // Bahor OK![32, 79, 75] — bo'sh joy, O va K harflarining kodlari. text() — Blob'ni ochib, ichini matn sifatida o'qiydi. U Promise qaytaradi, shuning uchun await. O'qish usullarini to'liq keyingi darsda ko'ramiz.
3.4 slice(): bo'lak kesish
blob.slice(boshi, oxiri, tur) — yangi, kichikroq Blob. Xuddi satrning slice i kabi: oxiri kirmaydi, manfiy son oxirdan sanaydi:
const greeting = new Blob(["Bahor OK!"], { type: "text/plain" });
const first = greeting.slice(0, 5);
const last = greeting.slice(-3);
console.log(first.size, await first.text()); // 5 Bahor
console.log(last.size, await last.text()); // 3 OK!
console.log(JSON.stringify(first.type)); // ""Ikki narsaga e'tibor bering. Birinchisi — kesilgan bo'lakning type i bo'sh: uchinchi argument berilmasa, tur ko'chmaydi. Ikkinchisi muhimroq: slice baytlarni nusxalamaydi. 2 GB lik videodan bo'lak kesish ham bir zumda bo'ladi — yangi Blob shunchaki "asl qutining 100-baytidan 200-baytigacha" degan yozuv. Katta faylni bo'laklab serverga yuborish shunga asoslanadi (Fayl yuklash va progress darsi).
Bo'sh joyni to'ldiring: new Blob(["abc"]).slice(1).size ning qiymati
Tekshirib ko'ring:
new Blob(["salom"])uchunblob.namenima qaytaradi?
Javob
undefined. Nom faqat File da bor. Blob — nomsiz quti. Sinovda Node 24 da ham name, ham lastModified undefined chiqdi. Nom kerak bo'lsa — new File([blob], "nomi.txt").
4. Obyekt URL: Blob'ga manzil berish
4.1 URL.createObjectURL()
Blob xotirada turibdi. Uni <img> ga ko'rsatish yoki havola qilish uchun manzil kerak — src va href faqat URL qabul qiladi.
URL.createObjectURL(blob) shunday manzil yaratadi. U obyekt URL (object URL) deyiladi va blob: bilan boshlanadi:
blob:https://example.com/3f1c9a0e-8d2b-4c6f-9e51-7a2d4b8c1e90Tarkibi: blob: + sahifaning origin'i + tasodifiy identifikator. Manzil faqat shu sahifa ichida ishlaydi. Uni boshqa tabga yoki do'stingizga yuborsangiz — ochilmaydi. U brauzer xotirasidagi Blob'ga ishora, xolos. Natija oynasida origin null bo'lgani uchun manzil blob:null/… ko'rinishida bo'ladi.
Blob faqat fayl tanlash maydonidan yoki new Blob() dan kelmaydi. fetch asoslari darsida "blob() bilan rasm va fayllarni keyin ishlatamiz" degan edik: javob tanasini response.blob() bilan Blob qilib olish mumkin. Mashq serveridagi /fayl 2 000 baytlik fayl beradi:
const response = await fetch(
"https://ilmhamroh.uz/api/mashq/fayl?hajm=2000&oraliq=0",
);
const blob = await response.blob();
console.log(blob.size); // 2000
console.log(blob.type); // application/octet-streamtype server yuborgan Content-Type sarlavhasidan olinadi. Brauzerda bunday Blob'ga ham obyekt URL berib, rasm bo'lsa <img> da ko'rsatish yoki yuklab berish mumkin.
4.2 «Bahor»: menyu belgisi xotiradan
Jasur aka har taom uchun kichik belgi xohlaydi: rangli doira va ichida harf. Rasm faylini chizish shart emas — SVG matnini Blob qilamiz va <img> ga beramiz:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
img { width: 96px; height: 96px; display: block;
margin-top: 0.75rem; }
input, button { font: inherit; padding: 0.3rem 0.6rem; }
</style>
<label for="dish">Taom nomi:</label>
<input id="dish" value="Osh" maxlength="20">
<button id="make" type="button">Belgi yasash</button>
<img id="badge" alt="">
<p id="url"></p>
<script>
const dishInput = document.getElementById("dish");
const badge = document.getElementById("badge");
let currentUrl = null;
function makeBadge() {
const name = dishInput.value.trim();
const letter = name.charAt(0).toUpperCase() || "?";
const svg = `<svg xmlns="http://www.w3.org/2000/svg"
width="96" height="96" viewBox="0 0 96 96">
<circle cx="48" cy="48" r="46" fill="#2e7d32"/>
<text x="48" y="62" font-size="44"
text-anchor="middle" fill="#fff"
font-family="sans-serif">${letter}</text></svg>`;
const blob = new Blob([svg], { type: "image/svg+xml" });
if (currentUrl !== null) URL.revokeObjectURL(currentUrl);
currentUrl = URL.createObjectURL(blob);
badge.src = currentUrl;
badge.alt = `${dishInput.value} belgisi`;
document.getElementById("url").textContent = currentUrl;
console.log(`Blob: ${blob.size} bayt, ${blob.type}`);
}
const makeButton = document.getElementById("make");
makeButton.addEventListener("click", makeBadge);
makeBadge();
</script>Qatorma-qator:
svg— oddiy matn: doira va harf.${letter}— taom nomining birinchi harfi.new Blob([svg], { type: "image/svg+xml" })— matn rasm faylga aylandi. Tur muhim: brauzer<img>da Blob'ni shu tur bo'yicha o'qiydi.URL.createObjectURL(blob)— Blob'ga manzil.badge.srcga beriladi va rasm chiqadi.URL.revokeObjectURL(currentUrl)— eski manzilni bo'shatish. Bu haqda pastda batafsil.
Sahifa ochilganda konsolda:
Blob: 269 bayt, image/svg+xmlTaom nomini "Manti" ga o'zgartirib, tugmani bosing — belgida "M" chiqadi. Manzil har safar yangi. Biz sinadik: rasm haqiqatan yuklandi (naturalWidth 96), manzil blob:null/ bilan boshlandi.
4.3 revokeObjectURL: xotirani qaytarish
Obyekt URL yaratilgach, brauzer Blob'ni xotirada ushlab turadi — manzil kimgadir kerak bo'lib qolishi mumkin. Sahifa yopilguncha yoki siz aytguncha. 100 ta rasm ko'rsatdingiz va revoke qilmadingiz — 100 ta Blob xotirada qoladi, hatto <img> lar o'chirilgan bo'lsa ham. Bu xotira sizishi (memory leak) — Xotira sizishlari darsidagi muammo.
URL.revokeObjectURL(url) — "bu manzil endi kerak emas". Shundan keyin manzil ishlamaydi, Blob'ni esa (boshqa hech kim ushlamasa) axlat yig'uvchi tozalaydi.
Qachon chaqirish kerak:
<img>uchun — rasm yuklangach (loadhodisasi) yoki rasm almashtirilganda. Yuqoridagi misolda — yangi belgi yasalganda eskisi bo'shatiladi.- Yuklab berish uchun — yuklash boshlangandan keyin (keyingi bo'limda).
flowchart LR
B["Blob<br/>(xotirada)"] -->|createObjectURL| U["blob: manzil"]
U --> I["img src"]
U --> A["a download"]
U -->|revokeObjectURL| X["manzil o'chdi,<br/>xotira bo'shaydi"]Nimaga qarang: manzil — Blob bilan foydalanuvchi o'rtasidagi "ko'prik". Ish tugagach ko'prikni olib tashlash sizning vazifangiz.
Tekshirib ko'ring:
img.src = URL.createObjectURL(blob)dan keyin darhol, keyingi qatordaURL.revokeObjectURL(img.src)yozildi. Rasm chiqadimi?
Javob
Yo'q. Biz Chrome 154 da sinadik: rasm load emas, error hodisasini oldi. src ni o'rnatish rasmni darhol yuklamaydi: yuklash keyinroq, alohida task'da boshlanadi. U paytda manzil allaqachon bekor qilingan. To'g'ri yo'l — img.addEventListener("load", () => URL.revokeObjectURL(img.src), { once: true }).
5. Yuklab berish: <a download>
5.1 download atributi
Havolaga download atributi qo'shilsa, brauzer manzilni ochmaydi, faylni yuklab oladi. Atribut qiymati — taklif qilinadigan fayl nomi:
<a href="menyu.pdf" download="bahor-menyu.pdf">
Menyuni yuklab olish
</a>download faqat shu saytdan yoki blob: / data: manzillar uchun ishlaydi. Boshqa saytdagi faylga qo'yilsa, brauzer uni e'tiborsiz qoldiradi va oddiy havola kabi ochadi. Bu himoya: begona sayt faylini "siznikiday" nom bilan tushirib bo'lmaydi.
Bizning Blob'ning manzili blob: — shuning uchun mos keladi. Retsept: Blob → obyekt URL → vaqtinchalik <a download> → click() → revoke.
5.2 «Bahor»: menyuni CSV qilib yuklab olish
CSV (Comma-Separated Values — vergul bilan ajratilgan qiymatlar) — jadvalni oddiy matn qilib yozish formati. Har qator — jadval qatori, ustunlar ajratgich bilan. Excel uni ochadi. Jasur akaning tugmasi:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
button { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<p>«Bahor» menyusi: 3 ta taom</p>
<button id="download" type="button">
Menyuni CSV qilib yuklab olish
</button>
<script>
const menu = [
{ name: "Osh", price: 35000 },
{ name: "Manti", price: 30000 },
{ name: "Lag'mon", price: 28000 },
];
function downloadFile(content, fileName, type) {
const blob = new Blob(content, { type });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName;
link.click();
setTimeout(() => URL.revokeObjectURL(url), 0);
console.log(`${fileName}: ${blob.size} bayt`);
}
const button = document.getElementById("download");
button.addEventListener("click", () => {
const rows = menu.map((dish) => `${dish.name};${dish.price}`);
const csv = ["Taom;Narx", ...rows].join("\r\n");
// BOM: Excel faylni UTF-8 deb taniydi (o' va g' buzilmaydi)
downloadFile(["\uFEFF", csv], "bahor-menyu.csv",
"text/csv;charset=utf-8");
});
</script>Qatorma-qator:
downloadFile— qayta ishlatiladigan funksiya: tarkib qismlari, nom, tur.document.createElement("a")— havola sahifaga qo'shilmaydi.link.click()uni shunchaki "bosadi" — DOM'da bo'lishi shart emas.setTimeout(() => URL.revokeObjectURL(url), 0)— darhol emas, keyingi task'da bo'shatamiz.click()yuklashni boshlaydi, lekin brauzer manzilni o'qishga ulgurishi kerak. Keyingi task'gacha ulguradi.join("\r\n")— qatorlar orasiga Windows qator oxiri (CRLF) qo'yiladi. CSV standarti aynan shuni tavsiya qiladi (Qator oxiri (CRLF/LF) darsi)."\uFEFF"— BOM (Byte Order Mark — "bayt tartibi belgisi"). Ko'rinmaydigan belgi, UTF-8 da 3 bayt. Excel uni ko'rib faylni UTF-8 deb taniydi. BOM'siz Excel faylni eski kodlashda o'qiydi: lotin harflari va apostrof to'g'ri chiqadi, lekin—,«»yoki kirill harflari buziladi. Ertaga menyuga shunday belgi qo'shilsa ham fayl buzilmasin — BOM doim qo'yiladi.;ajratgich — o'nlik kasrni vergul bilan yozadigan til sozlamalarida (rus, o'zbek) Windows'dagi Excel ko'pincha vergulni emas, nuqtali vergulni kutadi.
Tugmani bosganingizda brauzer bahor-menyu.csv faylini yuklab oladi va konsolga uning hajmi chiqadi:
bahor-menyu.csv: 51 baytBiz buni Chrome 154 da, yuklab olingan faylni ochib sinadik: fayl bahor-menyu.csv nomi bilan, 51 bayt bo'lib tushdi, boshida EF BB BF (BOM) baytlari bor edi. Sahifa hech qayerga o'tmadi. Natija oynasi allow-downloads ruxsati bilan ochilgan — shuning uchun bu yerda ham yuklab olish ishlaydi.
Server bitta ham so'rov olmadi. Ma'lumot brauzerda edi — fayl ham brauzerda yasaldi.
Diqqat:
link.click()ni foydalanuvchi bosishidan tashqarida (masalan, sahifa ochilishi bilan, taymerda) chaqirsangiz, brauzer "sayt fayl yuklamoqchi" deb ruxsat so'rashi yoki bloklashi mumkin. Yuklab berish — doim foydalanuvchi harakatiga javob.
Tekshirib ko'ring:
link.download = "menyu.csv"qatorini olib tashlasak nima bo'ladi?
Javob
Havola oddiy havolaga aylanadi: brauzer blob: manzilni yangi sahifa sifatida ochishga urinadi. CSV matn sifatida ko'rsatiladi yoki nomi tasodifiy identifikator bo'lgan fayl tushadi — brauzerga bog'liq. download — "och emas, saqla" degan buyruq.
5.3 Obyekt URL yoki data: URL
Blob'ga manzil berishning yana bir yo'li — data URL: butun tarkib manzilning o'zida, data:image/svg+xml;base64,PHN2Zy... ko'rinishida. Uni keyingi darsda FileReader bilan olamiz. Hozircha farqi:
Obyekt URL (blob:) |
Data URL (data:) |
|
|---|---|---|
| Uzunligi | ~60 belgi | fayl hajmidan ~33% katta |
| Yaratish | darhol, nusxasiz | butun faylni o'qib, kodlaydi |
| Yashash muddati | sahifa yopilguncha yoki revoke | doim (oddiy satr) |
| Qayerda | faqat shu sahifada | saqlash, yuborish mumkin |
Sahifada ko'rsatish va yuklab berish uchun — obyekt URL. Satr sifatida saqlash kerak bo'lsa (masalan, localStorage ga) — data URL.
6. Hujumchi nigohi
Fayl nomi va turi — foydalanuvchidan keladi. Demak, ular foydalanuvchi kiritgan matn kabi xavfli.
Hujum: nomdagi HTML. Hujumchi faylini shunday nomlaydi: <img src=x onerror=alert(1)>.jpg. Windows bunday nomga ruxsat bermaydi, lekin macOS va Linux'da < va > nomda bo'lishi mumkin. Sardor fayllar ro'yxatini innerHTML bilan chizsa:
// ❌ fayl nomi HTML sifatida o'qiladi
info.innerHTML += `<li>${file.name}</li>`;— nomdagi <img onerror> ishga tushadi. Bu XSS: begona kod sizning sahifangizda bajariladi. Fayllar ro'yxati keyinchalik boshqa foydalanuvchiga (masalan, adminga) ko'rsatilsa — uning brauzerida.
Himoya: nom — doim textContent bilan, xuddi «Fayl tanlang» misolidagidek. textContent hech narsani HTML deb o'qimaydi.
Hujum: soxta tur. type kengaytmadan olinadi — u hech narsani kafolatlamaydi. SVG Blob'ni <img> da ko'rsatish xavfsiz: <img> ichidagi SVG skriptlari ishlamaydi. Lekin o'sha SVG'ni innerHTML bilan sahifaga qo'ysangiz yoki obyekt URL'ini yangi tabda ochsangiz — skript ishlashi mumkin. Foydalanuvchi faylini faqat <img>, <video> kabi "xavfsiz idish"da ko'rsating.
Server tomonidagi himoya — baribir majburiy (Fayl yuklash xavfsizligi darsi, backend qismida).
7. Ko'p uchraydigan xatolar
7.1 FileList ni massiv deb o'ylash
input.files.map(...) → TypeError: ... is not a function. Tuzatish: [...input.files].
7.2 Hajmni belgilarda hisoblash
text.length — belgilar, blob.size — baytlar. O'zbekcha matnda farq kam, emoji va boshqa alifbolarda katta. Tuzatish: chegarani size bilan tekshiring.
7.3 revokeObjectURL ni unutish
Har yangi rasmda yangi manzil, eskisi bo'shatilmaydi — xotira o'sadi. Tuzatish: manzilni o'zgaruvchida saqlang va kerak bo'lmay qolganda revoke qiling.
7.4 Juda erta revoke
click() yoki src dan keyin darhol revoke — yuklash ulgurmaydi. Tuzatish: setTimeout(..., 0) yoki load hodisasi.
7.5 Boshqa saytdagi faylga download
<a href="https://boshqa-sayt.example/menyu.pdf" download> — fayl ochiladi, yuklanmaydi. Tuzatish: faylni o'z serveringizdan bering yoki fetch → blob() → obyekt URL. Ikkinchi yo'l faqat boshqa sayt CORS bilan ruxsat bersa ishlaydi.
8. Mashqlar
1-mashq (oson): Matn fayl
Node'da (shu yerda) new File() bilan "eslatma.txt" faylini yarating, tarkibi — "Ertaga 10:00 da bron", turi — "text/plain". Uning nomi, hajmi va matnini chiqaring.
Yechim
const note = new File(["Ertaga 10:00 da bron"], "eslatma.txt", {
type: "text/plain",
});
console.log(note.name); // eslatma.txt
console.log(note.size); // 20
console.log(await note.text()); // Ertaga 10:00 da bronMatnda faqat lotin harflari, raqamlar va bo'sh joy — har biri 1 bayt. Shuning uchun size belgilar soniga teng.
2-mashq (o'rta): Bronlar JSON fayli
Bronlar massivini bronlar.json fayli qilib yuklab beradigan tugma yozing. JSON chiroyli (2 bo'sh joy bilan) formatlansin. «Menyuni CSV qilib yuklab olish» misolidagi downloadFile naqshini ishlating, turi — "application/json".
Ishora: JSON.stringify(qiymat, null, 2) (JSON asoslari darsi).
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
button { font: inherit; padding: 0.4rem 0.8rem; }
</style>
<button id="save" type="button">Bronlarni yuklab olish</button>
<script>
const bookings = [
{ guest: "Malika", time: "19:00", people: 4 },
{ guest: "Bobur", time: "20:30", people: 2 },
];
function downloadFile(content, fileName, type) {
const blob = new Blob(content, { type });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName;
link.click();
setTimeout(() => URL.revokeObjectURL(url), 0);
console.log(`${fileName}: ${blob.size} bayt`);
}
document.getElementById("save").addEventListener("click", () => {
const json = JSON.stringify(bookings, null, 2);
downloadFile([json], "bronlar.json", "application/json");
});
</script>Tugmani bosganingizda brauzer bronlar.json ni yuklab oladi, konsolda bronlar.json: 139 bayt chiqadi (bosib sinalgan). JSON uchun BOM kerak emas: JSON standarti UTF-8 ni o'zi talab qiladi.
3-mashq (qiyin): Rasmlar galereyasi
Mehmon bir nechta rasm tanlaydi (multiple, accept="image/*"). Har biri kichik <img> bo'lib chiqsin (kengligi 120 px), ostida nomi. Talablar:
- Rasm bo'lmagan fayl (
type"image/"bilan boshlanmasa) o'tkazib yuborilsin. - Har rasm yuklangach, uning obyekt URL'i bo'shatilsin.
- Nom
textContentbilan yozilsin. - Konsolga:
Ko'rsatildi: N ta rasm.
Ishora: img.addEventListener("load", ..., { once: true }) (Listener opsiyalari), file.type.startsWith("image/").
Yechim
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
#gallery { display: flex; flex-wrap: wrap; gap: 0.75rem;
margin-top: 0.75rem; }
figure { margin: 0; width: 120px; }
figure img { width: 120px; height: 90px; object-fit: cover; }
figcaption { font-size: 0.8rem; overflow-wrap: anywhere; }
</style>
<label for="photos">Rasmlar:</label>
<input type="file" id="photos" accept="image/*" multiple>
<div id="gallery"></div>
<script>
const photos = document.getElementById("photos");
const gallery = document.getElementById("gallery");
photos.addEventListener("change", () => {
gallery.replaceChildren();
const images = [...photos.files]
.filter((file) => file.type.startsWith("image/"));
for (const file of images) {
const figure = document.createElement("figure");
const img = document.createElement("img");
const caption = document.createElement("figcaption");
const url = URL.createObjectURL(file);
img.addEventListener("load", () => URL.revokeObjectURL(url),
{ once: true });
img.src = url;
img.alt = file.name;
caption.textContent = file.name;
figure.append(img, caption);
gallery.append(figure);
}
console.log(`Ko'rsatildi: ${images.length} ta rasm`);
});
</script>[...photos.files] — FileList massivga aylandi, endi filter bor. load dan keyin revoke: rasm allaqachon chizilgan, manzil endi kerak emas. Biz PNG, JPG va .txt fayllarini tanlab sinadik: Ko'rsatildi: 2 ta rasm.
4-mashq: Vazifalar qadami — eksport faylga
vazifalar da "Eksport" qismi bor: «JSON qilib chiqarish» matnni textarea ga yozadi, foydalanuvchi uni nusxalaydi. Endi yonida «Faylga yuklab olish» tugmasi bo'ladi: bosilsa, o'sha JSON vazifalar-2026-10-05.json kabi fayl bo'lib tushadi. Fayl nomida — bugungi mahalliy sana.
vazifalar kanoni o'zbekcha nomlar bilan yozilgan — downloadFile bu yerda faylniYuklabBer.
1. Branch:
git switch -c feature/eksport-fayl2. Yangi fayl assets/js/fayl.js:
// @ts-check
// fayl.js — fayl yaratish va o'qish (Blob, File)
/**
* Matnni fayl qilib beradi: Blob → vaqtinchalik blob: URL →
* <a download> bosiladi. Sahifa hech qayerga o'tmaydi.
* @param {string} matn
* @param {string} nomi foydalanuvchi ko'radigan fayl nomi
* @param {string} [tur] MIME turi
*/
export function faylniYuklabBer(
matn,
nomi,
tur = "application/json",
) {
const blob = new Blob([matn], { type: tur });
const url = URL.createObjectURL(blob);
const havola = document.createElement("a");
havola.href = url;
havola.download = nomi;
havola.click();
// blob: URL Blob'ni xotirada ushlab turadi — bo'shatamiz. Keyingi
// vazifada: yuklash shu paytgacha boshlangan bo'ladi
setTimeout(() => URL.revokeObjectURL(url), 0);
}Telefon ekraniga sig'ishi uchun parametrlar bu yerda alohida qatorlarda; kanon faylda ular bitta qatorda (Prettier shunday formatlaydi). Darsdagi downloadFile bilan solishtiring — bir xil retsept. Izohdagi "keyingi vazifada" — setTimeout(..., 0) ning keyingi task'i (kanon izohlari o'zbekcha). Fayl jsconfig.json ning include ro'yxatiga qo'shiladi — npm run tip uni ham tekshirsin.
3. paket.js — fayl nomi:
/**
* Eksport fayli nomi — sana bilan, tartiblaganda xronologik turadi.
* Mahalliy sana (UTC emas): kechasi soat 2 da olingan fayl kechagi
* sanani olmasin
* @param {Date} [sana]
* @returns {string} masalan "vazifalar-2026-10-05.json"
*/
export function eksportFaylNomi(sana = new Date()) {
const oy = String(sana.getMonth() + 1).padStart(2, "0");
const kun = String(sana.getDate()).padStart(2, "0");
return `vazifalar-${sana.getFullYear()}-${oy}-${kun}.json`;
}Nega toISOString().slice(0, 10) emas? U UTC sanasini beradi. Toshkent UTC+5: 5-oktabr kechasi soat 2 da UTC'da hali 4-oktabr. Fayl kechagi sana bilan tushardi (Date va vaqt zonalari darsidagi tuzoq). getMonth() va getDate() — mahalliy.
4. index.html — tugma va oldindan yuklash:
<button type="button"
id="eksport-fayl">Faylga yuklab olish</button><link rel="modulepreload" href="assets/js/fayl.js">render.js ga: export const eksportFayl = document.getElementById("eksport-fayl");.
5. asosiy.js:
import {
eksportMatni,
eksportFaylNomi,
paketniOqi,
} from "./paket.js";
import { faylniYuklabBer } from "./fayl.js";
eksportFayl.addEventListener("click", () => {
const nomi = eksportFaylNomi();
faylniYuklabBer(eksportMatni(holat.vazifalar), nomi);
elonQil(`${nomi} yuklab olindi.`);
});Fayl tarkibi — «JSON qilib chiqarish» dagi eksportMatni ning o'zi. Ya'ni yuklangan faylni keyingi darsda import qilish mumkin bo'ladi. elonQil — ekran o'quvchi uchun e'lon: Malika (NVDA bilan) yuklash bo'lganini eshitadi.
6. Test. tekshiruv/paket.test.js ga bitta test:
describe("eksportFaylNomi", () => {
test("mahalliy sana, oy va kun ikki xonali", () => {
assert.equal(
eksportFaylNomi(new Date(2026, 9, 5, 2, 30)),
"vazifalar-2026-10-05.json",
);
assert.equal(
eksportFaylNomi(new Date(2027, 0, 9)),
"vazifalar-2027-01-09.json",
);
});
});new Date(2026, 9, 5, 2, 30) — mahalliy vaqt bo'yicha 5-oktabr, soat 02:30 (oylar 0 dan: 9 — oktabr). Aynan "kechasi soat 2" holati. Natija — 71/71; lint, format:check, tip — toza.
7. Brauzerda (Live Server). Kanon tekshiruvida (Chrome 154, yuklab olingan fayl bilan):
✅ eksport fayl: nomi: ["vazifalar-2026-10-05.json"]
✅ eksport fayl: tarkibi = JSON matni: true
✅ eksport fayl: e'lon: "vazifalar-2026-10-05.json yuklab olindi."
✅ eksport fayl: sahifa joyida: "/"Yana bitta qator Blob turi application/json ekanini va blob: manzil bo'shatilganini tekshiradi. O'zingiz: tugmani bosing, yuklangan faylni VS Code'da oching — ichida «JSON qilib chiqarish» dagi matn. Brauzer manzil qatori o'zgarmaganiga e'tibor bering.
8. Commit va PR:
git add assets/js/fayl.js assets/js/paket.js assets/js/asosiy.js \
assets/js/render.js index.html jsconfig.json tekshiruv/paket.test.js
git commit -m "feat: eksport .json fayl qilib yuklab olinadi" \
-m "Blob, createObjectURL, revokeObjectURL."
git push -u origin feature/eksport-fayl
gh pr create --fill
gh pr merge --mergeCommit sarlavhasi 72 belgidan oshmasin (Git qoidasi) — shuning uchun texnik tafsilot ikkinchi -m ga, tanaga ko'chdi.
9. Real ishda
- Eksport tugmalari. Hisobotni CSV/Excel'ga, chekni PDF'ga, sozlamalarni JSON'ga — ko'p ilovalarda bu serversiz, aynan shu retsept bilan qilinadi. SheetJS kabi kutubxonalar haqiqiy
.xlsxyasaydi, lekin oxirida baribirBlob+<a download>. - Rasm oldindan ko'rish. Telegram Web, Instagram — rasm tanlanganda u darhol ko'rinadi. Bu obyekt URL: fayl hali serverga ketmagan.
fetch→blob(). Serverdan kelgan rasm yoki PDF niresponse.blob()bilan olib, obyekt URL bilan ko'rsatish (fetchasoslari).- Intervyu. "Blob va File farqi?", "
createObjectURLdan keyin nima qilish kerak?", "Serversiz fayl qanday yuklab beriladi?" — frontend intervyularida uchraydi.
Xulosa
Blob— hajmi va turi bor baytlar bo'lagi;File— nomi va sanasi qo'shilgan Blob.input.files—FileList(massiv emas);typekengaytmadan taxmin qilinadi,size— baytlarda.new Blob(qismlar, { type })satr, typed array va Blob'lardan yig'adi;slice()nusxasiz kesadi.URL.createObjectURL(blob)—blob:manzil; ish tugagachURL.revokeObjectURL().- Yuklab berish: Blob → obyekt URL →
<a download>→click()→ revoke. - Fayl nomini doim
textContentbilan ko'rsating.
Keyingi dars: Faylni o'qish va oldindan ko'rish — Blob'ni "ochish": matn, baytlar va rasm sifatida o'qish, yuklashdan oldin hajm va turni tekshirish.
Manbalar
- W3C: File API — w3.org/TR/FileAPI
- MDN:
Blob,File,FileList,URL.createObjectURL()— developer.mozilla.org - HTML Living Standard: "Downloading resources" (
downloadatributi) — html.spec.whatwg.org
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!