16-bo‘lim

Fayllar bilan ishlash

fopen rejimlari, matn va ikkilik fayllar, satr bo'yicha o'qish, fprintf va fscanf, xatolarni boshqarish va fayl ichida harakatlanish.

🕑 17 daqiqa o‘qish 📄 798 so‘z 👁 3 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Fayl ochish va yopish
  2. Faylga yozish
  3. Fayldan o'qish
  4. Satr bo'yicha o'qish
  5. Strukturalarni faylga saqlash
  6. Ikkilik fayllar
  7. Fayl ichida harakatlanish
  8. Fayl hajmini aniqlash
  9. Xatolarni to'g'ri boshqarish
  10. Faylni satrma-satr nusxalash
  11. Xulosa

Dastur tugagach, xotiradagi ma'lumot yo'qoladi. Uni saqlab qolish uchun fayl kerak.

Fayl ochish va yopish #

C
FILE *fayl = fopen("malumot.txt", "r");

if (fayl == NULL) {
    /* fayl ochilmadi */
}

fclose(fayl);
RejimMa'nosiFayl yo'q bo'lsaMavjud bo'lsa
"r"O'qishNULL qaytaradiochadi
"w"Yozishyaratadibutunlay o'chiradi
"a"Oxiriga qo'shishyaratadioxiriga yozadi
"r+"O'qish va yozishNULL qaytaradiochadi
"w+"O'qish va yozishyaratadio'chiradi
"a+"O'qish va qo'shishyaratadioxiriga yozadi
"rb"Ikkilik o'qishNULLochadi
"wb"Ikkilik yozishyaratadio'chiradi
"w" rejimi faylni o'chiradi
C
FILE *f = fopen("muhim.txt", "w");    /* mavjud mazmun YO'QOLDI */

Bu eng ko'p uchraydigan halokatli xato. Mavjud faylga qo'shmoqchi bo'lsangiz - "a" ishlating.

Faylga yozish #

C
#include <stdio.h>

int main(void) {
    FILE *fayl = fopen("talabalar.txt", "w");

    if (fayl == NULL) {
        fprintf(stderr, "Faylni ochib bo'lmadi\n");
        return 1;
    }

    fprintf(fayl, "Husanboy Qodirov 25 4.60\n");
    fprintf(fayl, "Malika Yusupova 21 4.90\n");
    fprintf(fayl, "Nodira Sobirova 24 4.30\n");

    fclose(fayl);

    printf("Fayl yozildi.\n");
    return 0;
}
Natija
Fayl yozildi.
fprintf - printf ning fayl varianti
C
printf("Salom\n");                 /* ekranga */
fprintf(stdout, "Salom\n");        /* xuddi shu narsa */
fprintf(stderr, "Xato!\n");        /* xatolar oqimiga */
fprintf(fayl, "Salom\n");          /* faylga */

Xato xabarlarini doim stderr ga yozing. Shunda ular alohida yo'naltirilishi mumkin:

Terminal
./dastur > natija.txt 2> xatolar.txt

Fayldan o'qish #

C
#include <stdio.h>

int main(void) {
    FILE *yozish = fopen("sonlar.txt", "w");

    if (yozish == NULL) {
        return 1;
    }

    for (int i = 1; i <= 5; i++) {
        fprintf(yozish, "%d\n", i * 11);
    }

    fclose(yozish);

    FILE *oqish = fopen("sonlar.txt", "r");

    if (oqish == NULL) {
        fprintf(stderr, "Fayl topilmadi\n");
        return 1;
    }

    int son;
    int yigindi = 0;

    while (fscanf(oqish, "%d", &son) == 1) {
        printf("O'qildi: %d\n", son);
        yigindi += son;
    }

    fclose(oqish);

    printf("Yig'indi: %d\n", yigindi);
    return 0;
}
Natija
O'qildi: 11
O'qildi: 22
O'qildi: 33
O'qildi: 44
O'qildi: 55
Yig'indi: 165
fscanf natijasini tekshiring
C
while (fscanf(fayl, "%d", &son) == 1) { ... }

fscanf muvaffaqiyatli o'qilgan qiymatlar sonini qaytaradi. Fayl tugaganda yoki format mos kelmaganda bu son kamayadi va sikl to'xtaydi.

while (!feof(fayl)) yozmang - bu klassik xato. feof fayl oxiriga yetilgandan keyin rost bo'ladi, shuning uchun oxirgi element ikki marta qayta ishlanadi.

Satr bo'yicha o'qish #

C
#include <stdio.h>
#include <string.h>

int main(void) {
    FILE *yozish = fopen("shaharlar.txt", "w");

    if (yozish == NULL) {
        return 1;
    }

    fprintf(yozish, "Namangan\nToshkent\nSamarqand\nBuxoro\n");
    fclose(yozish);

    FILE *oqish = fopen("shaharlar.txt", "r");

    if (oqish == NULL) {
        return 1;
    }

    char qator[256];
    int raqam = 1;

    while (fgets(qator, sizeof(qator), oqish) != NULL) {
        qator[strcspn(qator, "\n")] = '\0';      /* qator oxirini kesamiz */
        printf("%d. %s (%zu harf)\n", raqam++, qator, strlen(qator));
    }

    fclose(oqish);
    return 0;
}
Natija
1. Namangan (8 harf)
2. Toshkent (8 harf)
3. Samarqand (9 harf)
4. Buxoro (6 harf)
fgets - fayl o'qishning eng ishonchli usuli

fgets bufer hajmini biladi va undan oshib ketmaydi. Har bir qatorni alohida o'qib, keyin uni tahlil qilish - eng xavfsiz yondashuv.

Uzun qator bufergacha sig'masa, fgets uni bo'lib o'qiydi va keyingi chaqiruvda davomini beradi.

Strukturalarni faylga saqlash #

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char ism[40];
    int yosh;
    double baho;
} Talaba;

int saqla(const char *fayl_nomi, const Talaba guruh[], int soni) {
    FILE *f = fopen(fayl_nomi, "w");

    if (f == NULL) {
        return 0;
    }

    for (int i = 0; i < soni; i++) {
        fprintf(f, "%s;%d;%.2f\n", guruh[i].ism, guruh[i].yosh, guruh[i].baho);
    }

    fclose(f);
    return 1;
}

int yukla(const char *fayl_nomi, Talaba guruh[], int maks) {
    FILE *f = fopen(fayl_nomi, "r");

    if (f == NULL) {
        return 0;
    }

    char qator[200];
    int soni = 0;

    while (soni < maks && fgets(qator, sizeof(qator), f) != NULL) {
        qator[strcspn(qator, "\n")] = '\0';

        char *ism = strtok(qator, ";");
        char *yosh = strtok(NULL, ";");
        char *baho = strtok(NULL, ";");

        if (ism == NULL || yosh == NULL || baho == NULL) {
            continue;                            /* buzilgan qatorni o'tkazamiz */
        }

        strncpy(guruh[soni].ism, ism, sizeof(guruh[soni].ism) - 1);
        guruh[soni].ism[sizeof(guruh[soni].ism) - 1] = '\0';
        guruh[soni].yosh = atoi(yosh);
        guruh[soni].baho = atof(baho);
        soni++;
    }

    fclose(f);
    return soni;
}

int main(void) {
    Talaba asl[] = {
        {"Husanboy Qodirov", 25, 4.60},
        {"Malika Yusupova",  21, 4.90},
        {"Nodira Sobirova",  24, 4.30}
    };

    if (!saqla("guruh.csv", asl, 3)) {
        fprintf(stderr, "Saqlab bo'lmadi\n");
        return 1;
    }

    Talaba yuklangan[10];
    int soni = yukla("guruh.csv", yuklangan, 10);

    printf("%d ta yozuv yuklandi:\n", soni);

    for (int i = 0; i < soni; i++) {
        printf("  %-18s %3d %.2f\n",
               yuklangan[i].ism, yuklangan[i].yosh, yuklangan[i].baho);
    }

    return 0;
}
Natija
3 ta yozuv yuklandi:
  Husanboy Qodirov    25 4.60
  Malika Yusupova     21 4.90
  Nodira Sobirova     24 4.30
Kerakli sarlavhalarni unutmang

Bu misolda uchta sarlavha ishlatilgan:

SarlavhaNima uchun
stdio.hfopen, fprintf, fgets
stdlib.hatoi, atof
string.hstrtok, strncpy, strcspn

stdlib.h ni unutsangiz, atoi noto'g'ri talqin qilinadi va natija kutilmagan bo'ladi. -Wall bayrog'i bu haqda ogohlantiradi - shuning uchun ogohlantirishlarni hech qachon e'tiborsiz qoldirmang.

strtok asl satrni buzadi

strtok ajratuvchi belgilar o'rniga '\0' yozadi. Ya'ni u satrni o'zgartiradi.

Shuning uchun uni doimiy satrga qo'llab bo'lmaydi:

C
strtok("a;b;c", ";");        /* QULAYDI: literal o'zgartirib bo'lmaydi */

Bizning misolda qator - o'zgaruvchan massiv, shuning uchun xavfsiz.

Ikkilik fayllar #

C
#include <stdio.h>

typedef struct {
    char ism[40];
    int yosh;
    double baho;
} Talaba;

int main(void) {
    Talaba asl[] = {
        {"Husanboy Qodirov", 25, 4.60},
        {"Malika Yusupova",  21, 4.90}
    };

    FILE *yozish = fopen("guruh.bin", "wb");

    if (yozish == NULL) {
        return 1;
    }

    fwrite(asl, sizeof(Talaba), 2, yozish);
    fclose(yozish);

    Talaba yuklangan[2];
    FILE *oqish = fopen("guruh.bin", "rb");

    if (oqish == NULL) {
        return 1;
    }

    size_t oqilgan = fread(yuklangan, sizeof(Talaba), 2, oqish);
    fclose(oqish);

    printf("%zu ta yozuv o'qildi:\n", oqilgan);

    for (size_t i = 0; i < oqilgan; i++) {
        printf("  %-18s %3d %.2f\n",
               yuklangan[i].ism, yuklangan[i].yosh, yuklangan[i].baho);
    }

    return 0;
}
Natija
2 ta yozuv o'qildi:
  Husanboy Qodirov    25 4.60
  Malika Yusupova     21 4.90
Matn fayli va ikkilik fayl Matn fayli ✔ Odam o'qiy oladi ✔ Har qanday tahrirchida ochiladi ✔ Boshqa dasturlar tushunadi ✖ Kattaroq hajm ✖ O'qish sekinroq Ikkilik fayl ✔ Ixcham va tez ✔ Aniq nusxa saqlanadi ✖ Odam o'qiy olmaydi ✖ Platformaga bog'liq ✖ Struktura o'zgarsa - buziladi
Sozlama va jurnal uchun matn, katta ma'lumot uchun ikkilik
Ikkilik fayl ko'chma emas

fwrite strukturani xotiradagi ko'rinishi bilan yozadi - padding bilan birga.

Shuning uchun bir kompyuterda yozilgan fayl boshqasida noto'g'ri o'qilishi mumkin:

  • turli baytlar tartibi (endianness);
  • turli tekislash qoidalari;
  • turli int hajmi.

Fayl boshqa tizimga ko'chishi kerak bo'lsa - matn formatidan (CSV, JSON) foydalaning.

Shuningdek, strukturada ko'rsatkich bo'lsa, uni fwrite bilan saqlab bo'lmaydi: manzil boshqa ishga tushirishda ma'nosiz bo'ladi.

Fayl ichida harakatlanish #

C
#include <stdio.h>

int main(void) {
    FILE *f = fopen("alifbo.txt", "w+");

    if (f == NULL) {
        return 1;
    }

    fputs("ABCDEFGHIJ", f);

    fseek(f, 0, SEEK_SET);              /* boshiga */
    printf("Birinchi belgi : %c\n", (char) fgetc(f));

    fseek(f, 4, SEEK_SET);              /* boshidan 4 bayt */
    printf("5-belgi        : %c\n", (char) fgetc(f));

    fseek(f, -2, SEEK_END);             /* oxiridan 2 bayt orqaga */
    printf("Oxiridan 2-si  : %c\n", (char) fgetc(f));

    fseek(f, 0, SEEK_END);
    printf("Fayl hajmi     : %ld bayt\n", ftell(f));

    fclose(f);
    return 0;
}
Natija
Birinchi belgi : A
5-belgi        : E
Oxiridan 2-si  : I
Fayl hajmi     : 10 bayt
FunksiyaNima qiladi
fseek(f, siljish, boshlanish)Ko'rsatkichni ko'chiradi
ftell(f)Joriy o'rinni qaytaradi
rewind(f)Boshiga qaytaradi
SEEK_SETFayl boshi
SEEK_CURJoriy o'rin
SEEK_ENDFayl oxiri

Fayl hajmini aniqlash #

C
#include <stdio.h>

long fayl_hajmi(const char *nom) {
    FILE *f = fopen(nom, "rb");

    if (f == NULL) {
        return -1;
    }

    fseek(f, 0, SEEK_END);
    long hajm = ftell(f);
    fclose(f);

    return hajm;
}

int main(void) {
    FILE *f = fopen("sinov.txt", "w");

    if (f == NULL) {
        return 1;
    }

    fputs("Salom, dunyo!", f);
    fclose(f);

    long hajm = fayl_hajmi("sinov.txt");

    if (hajm >= 0) {
        printf("Fayl hajmi: %ld bayt\n", hajm);
    } else {
        printf("Faylni ochib bo'lmadi\n");
    }

    return 0;
}
Natija
Fayl hajmi: 13 bayt

Xatolarni to'g'ri boshqarish #

C
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(void) {
    FILE *f = fopen("mavjud_emas_12345.txt", "r");

    if (f == NULL) {
        fprintf(stderr, "Xato: %s\n", strerror(errno));
        printf("Fayl ochilmadi - dastur davom etadi\n");
        return 0;
    }

    fclose(f);
    return 0;
}
Natija
Xato: No such file or directory
Fayl ochilmadi - dastur davom etadi
errno va strerror

Standart funksiya xato qilganda errno global o'zgaruvchisiga xato kodini yozadi. strerror uni o'qishli matnga aylantiradi:

Natija
Xato: No such file or directory

perror esa buni bir qadamda qiladi:

C
if (f == NULL) {
    perror("mavjud_emas.txt");
}

Natija: mavjud_emas.txt: No such file or directory

fclose ni unutmang

Har bir fopen uchun bitta fclose bo'lishi kerak. Aks holda:

  • yozilgan ma'lumot buferda qolib ketishi mumkin;
  • operatsion tizim resursi band bo'lib qoladi;
  • ko'p fayl ochsangiz, chegaraga yetasiz.

Ayniqsa erta qaytishlarda ehtiyot bo'ling:

C
FILE *f = fopen("a.txt", "r");
if (f == NULL) return 1;

if (biror_shart) {
    return 1;          /* XATO: fayl yopilmadi */
}

fclose(f);

To'g'ri yo'l - qaytishdan oldin yopish:

C
if (biror_shart) {
    fclose(f);
    return 1;
}

Faylni satrma-satr nusxalash #

C
#include <stdio.h>

int nusxala(const char *manba, const char *maqsad) {
    FILE *m = fopen(manba, "rb");

    if (m == NULL) {
        return 0;
    }

    FILE *n = fopen(maqsad, "wb");

    if (n == NULL) {
        fclose(m);
        return 0;
    }

    char bufer[4096];
    size_t oqilgan;

    while ((oqilgan = fread(bufer, 1, sizeof(bufer), m)) > 0) {
        if (fwrite(bufer, 1, oqilgan, n) != oqilgan) {
            fclose(m);
            fclose(n);
            return 0;
        }
    }

    fclose(m);
    fclose(n);
    return 1;
}

int main(void) {
    FILE *f = fopen("asl.txt", "w");

    if (f == NULL) {
        return 1;
    }

    fputs("Bu fayl nusxalanadi.\nIkkinchi qator.\n", f);
    fclose(f);

    if (nusxala("asl.txt", "nusxa.txt")) {
        printf("Nusxalandi.\n");

        FILE *tekshir = fopen("nusxa.txt", "r");
        char qator[100];

        while (fgets(qator, sizeof(qator), tekshir) != NULL) {
            printf("  %s", qator);
        }

        fclose(tekshir);
    }

    return 0;
}
Natija
Nusxalandi.
  Bu fayl nusxalanadi.
  Ikkinchi qator.
Amaliy topshiriq
  1. Faylga o'z ismingizni yozing va uni qayta o'qing.
  2. "w" rejimida mavjud faylni ochib, mazmuni yo'qolishini ko'ring.
  3. "a" rejimi bilan faylga qo'shimcha qatorlar qo'shing.
  4. Fayldagi qatorlar sonini hisoblang.
  5. Fayldagi so'zlar sonini hisoblang.
  6. CSV formatida talabalar ro'yxatini saqlang va yuklang.
  7. strtok bilan CSV qatorini bo'laklarga ajrating.
  8. Strukturani ikkilik faylga saqlang va o'qing.
  9. fseek va ftell bilan fayl hajmini aniqlang.
  10. Faylni nusxalovchi dastur yozing (buferli o'qish bilan).

Xulosa #

  • fopen fayl ochadi, fclose yopadi - har biriga juft kerak.
  • fopen natijasini doim NULL ga tekshiring.
  • "w" rejimi mavjud faylni o'chiradi - qo'shish uchun "a".
  • fprintf / fscanf - matn bilan, fwrite / fread - ikkilik bilan.
  • fscanf natijasini tekshiring; while (!feof(f)) yozmang.
  • fgets eng ishonchli o'qish usuli - bufer hajmini biladi.
  • strtok asl satrni o'zgartiradi.
  • Ikkilik fayl ko'chma emas - boshqa tizimda buzilishi mumkin.
  • fseek va ftell bilan fayl ichida harakatlanish mumkin.
  • Xato sababini strerror(errno) yoki perror beradi.
  • Erta qaytishlarda faylni yopishni unutmang.

Keyingi bo'limda preprotsessor va ko'p faylli loyihalarni ko'ramiz.

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.