5-bo‘lim
Fayllar bilan ishlash
fs/promises bilan o'qish va yozish, papkalar, JSON saqlash, xatolarni ushlash va existsSync nima uchun yomon.
Ushbu bo‘lim mundarijasi
Fayl tizimi bilan ishlash - Node ning brauzerdan eng katta farqi.
Buning uchun node:fs moduli bor.
Uchta shakl #
fs moduli uch xil ko'rinishda keladi:
| Import | Uslub |
|---|---|
node:fs/promises | await - tavsiya etiladi |
node:fs | Qayta chaqiruv (callback) |
node:fs (...Sync) | Bloklaydigan |
Bu darslikda birinchisi ishlatiladi.
Yozish va o'qish #
import { writeFile, readFile, appendFile, rm } from "node:fs/promises";
await writeFile("qaydlar.txt", "Birinchi qator\n", "utf8");
await appendFile("qaydlar.txt", "Ikkinchi qator\n", "utf8");
const mazmun = await readFile("qaydlar.txt", "utf8");
console.log(mazmun.trimEnd());
console.log("Qatorlar:", mazmun.trimEnd().split("\n").length);
await rm("qaydlar.txt");
Birinchi qator
Ikkinchi qator
Qatorlar: 2
| Funksiya | Nima qiladi |
|---|---|
writeFile | Yozadi (ustiga yozadi) |
appendFile | Oxiriga qo'shadi |
readFile | O'qiydi |
rm | O'chiradi |
readFile ni kodlashsiz chaqirsangiz, u satr emas, Buffer
qaytaradi:
const xom = await readFile("fayl.txt");
console.log(typeof xom); // object
Buffer - xom baytlar. Rasm yoki arxiv uchun aynan shu kerak, matn
uchun esa "utf8" bering.
Buni unutish odatiy xato: keyin mazmun.split(...) ishlamay qoladi
va sabab darhol ravshan bo'lmaydi.
writeFile ustiga yozadi #
import { writeFile, readFile, rm } from "node:fs/promises";
await writeFile("sinov.txt", "birinchi mazmun", "utf8");
await writeFile("sinov.txt", "ikkinchi", "utf8");
console.log(await readFile("sinov.txt", "utf8"));
await writeFile("sinov.txt", " qo'shildi", { flag: "a" });
console.log(await readFile("sinov.txt", "utf8"));
await rm("sinov.txt");
ikkinchi
ikkinchi qo'shildi
writeFile so'ramasdan eski mazmunni yo'q qiladi. { flag: "a" }
bersangiz, u appendFile kabi ishlaydi.
Papkalar #
import { mkdir, writeFile, readdir, rm } from "node:fs/promises";
await mkdir("sinov/ichki", { recursive: true });
await writeFile("sinov/b.txt", "B", "utf8");
await writeFile("sinov/a.txt", "A", "utf8");
await writeFile("sinov/ichki/c.txt", "C", "utf8");
const fayllar = await readdir("sinov");
console.log(fayllar.sort());
const hammasi = await readdir("sinov", { recursive: true });
console.log(hammasi.sort().length);
await rm("sinov", { recursive: true, force: true });
[ 'a.txt', 'b.txt', 'ichki' ]
4
{ recursive: true } mkdir da ota-papkalarni ham yaratadi, rm da
esa butun daraxtni o'chiradi.
Yuqorida .sort() bejiz yozilmagan.
readdir fayllarni operatsion tizim bergan tartibda qaytaradi.
Linux da bu ko'pincha alifbo tartibi emas, balki fayl tizimining
ichki tartibi. Boshqa kompyuterda natija boshqacha bo'lishi mumkin.
Tartib muhim bo'lsa - masalan, hisobot yoki migratsiyalar ro'yxati - har doim o'zingiz saralang.
Bu darslikdagi hamma misol shu qoidaga amal qiladi.
Fayl haqida ma'lumot #
import { writeFile, stat, rm } from "node:fs/promises";
await writeFile("olcham.txt", "12345", "utf8");
const holat = await stat("olcham.txt");
console.log("Hajmi:", holat.size);
console.log("Faylmi:", holat.isFile());
console.log("Papkami:", holat.isDirectory());
console.log("Vaqt bormi:", holat.mtime instanceof Date);
await rm("olcham.txt");
Hajmi: 5
Faylmi: true
Papkami: false
Vaqt bormi: true
mtime ning o'zi chop etilmadi - u har safar boshqacha bo'lardi.
JSON saqlash #
import { writeFile, readFile, rm } from "node:fs/promises";
const talabalar = [
{ ism: "Malika", ball: 88 },
{ ism: "Husanboy", ball: 92 },
];
await writeFile("talabalar.json", JSON.stringify(talabalar, null, 2));
const xom = await readFile("talabalar.json", "utf8");
const qayta = JSON.parse(xom);
console.log(qayta.length);
console.log(qayta[1].ism, qayta[1].ball);
console.log(xom.split("\n").length > 1);
await rm("talabalar.json");
2
Husanboy 92
true
JSON.stringify(qiymat, null, 2) - uchinchi argument chekinish
beradi va faylni odam o'qiy oladigan qiladi.
Xatolarni ushlash #
import { readFile } from "node:fs/promises";
try {
await readFile("yoq-bunday-fayl.txt", "utf8");
} catch (xato) {
console.log("Kod:", xato.code);
console.log("Topilmadimi:", xato.code === "ENOENT");
console.log("Xato turi:", xato instanceof Error);
}
Kod: ENOENT
Topilmadimi: true
Xato turi: true
Node ning fayl xatolarida code maydoni bo'ladi. Eng ko'p
uchraydiganlari:
| Kod | Ma'nosi |
|---|---|
ENOENT | Fayl yoki papka yo'q |
EACCES | Ruxsat yetmaydi |
EEXIST | Allaqachon mavjud |
EISDIR | Fayl kutilgan edi, papka keldi |
ENOTEMPTY | Papka bo'sh emas |
Xato xabari tilga va Node versiyasiga qarab o'zgarishi mumkin.
code esa barqaror - u operatsion tizimdan keladi.
if (xato.code === "ENOENT") {
// fayl yo'q - bu normal bo'lishi mumkin
} else {
throw xato; // boshqa xato - yuqoriga uzating
}
Eng muhimi: hamma xatoni bir xil qabul qilmang. "Fayl yo'q" - ko'pincha kutilgan hol, "ruxsat yo'q" esa jiddiy muammo.
existsSync nima uchun yomon #
import { writeFile, readFile, rm } from "node:fs/promises";
async function xavfsizOqi(yol) {
try {
return await readFile(yol, "utf8");
} catch (xato) {
if (xato.code === "ENOENT") return null;
throw xato;
}
}
await writeFile("bor.txt", "mazmun", "utf8");
console.log(await xavfsizOqi("bor.txt"));
console.log(await xavfsizOqi("yoq.txt"));
await rm("bor.txt");
mazmun
null
Ko'p qo'llanmalarda shunday yoziladi:
if (existsSync(yol)) {
const mazmun = await readFile(yol, "utf8");
}
Muammo: tekshiruv bilan o'qish orasida vaqt o'tadi. O'sha
oniqda boshqa jarayon faylni o'chirib yuborishi mumkin - va
readFile baribir yiqiladi.
Bu TOCTOU (tekshiruvdan foydalanishgacha) deb ataladi.
To'g'ri yondashuv - yuqoridagi kabi: shunchaki urinib ko'ring
va ENOENT ni ushlang. Bu tezroq ham, ishonchliroq ham.
Nusxalash va nom o'zgartirish #
import { writeFile, copyFile, rename, readdir, rm } from "node:fs/promises";
import { mkdir } from "node:fs/promises";
await mkdir("ish", { recursive: true });
await writeFile("ish/asl.txt", "mazmun", "utf8");
await copyFile("ish/asl.txt", "ish/nusxa.txt");
await rename("ish/nusxa.txt", "ish/yangi-nom.txt");
console.log((await readdir("ish")).sort());
await rm("ish", { recursive: true, force: true });
[ 'asl.txt', 'yangi-nom.txt' ]
rename faylni ko'chirish uchun ham ishlatiladi - yangi yo'l boshqa
papkada bo'lsa, fayl o'sha yerga o'tadi.
Katta fayllar haqida #
10 KB uchun bu muammo emas. 2 GB uchun esa dastur xotirasi tugaydi va jarayon o'ladi.
Katta fayllar uchun oqimlar (streams) ishlatiladi: fayl bo'laklab o'qiladi va xotirada faqat bitta bo'lak turadi.
Buni 9-bo'limda batafsil ko'ramiz.
Oddiy qoida: fayl hajmini oldindan bilmasangiz yoki u foydalanuvchidan kelsa - oqim ishlating.
- Faylga yozib, uni qayta o'qing.
"utf8"ni tushirib qoldirib, natija turini ko'ring.appendFilebilan qator qo'shing.writeFileeski mazmunni yo'q qilishini isbotlang.{ recursive: true }bilan ichma-ich papka yarating.readdirnatijasini saralab chiqaring.statbilan fayl hajmini oling.- Obyektni JSON qilib saqlab, qayta o'qing.
- Mavjud bo'lmagan faylni o'qib,
xato.codeni chiqaring. ENOENTni ushlab,nullqaytaradigan funksiya yozing.
Xulosa #
node:fs/promises- zamonaviy,awaitbilan ishlaydigan shakl.- Matn uchun
"utf8"bering, aks holdaBufferkeladi. writeFileustiga yozadi; qo'shish uchunappendFileyoki{ flag: "a" }.{ recursive: true }papka daraxtini yaratadi va o'chiradi.readdirtartibni kafolatlamaydi - har doim o'zingiz saralang.- Fayl xatolarini
xato.codebo'yicha ajrating, matn bo'yicha emas. existsSync+ o'qish - poyga holati; shunchaki urinib ko'ring vaENOENTni ushlang.- Katta fayllar uchun
readFileemas, oqim kerak.
Keyingi bo'limda yo'llar va process bilan ishlaymiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.