18-bo‘lim

Fayllar va kirish-chiqish

Path va Files sinflari, matn o'qish va yozish, kodlash muammosi, kataloglar bilan ishlash, oqim sifatida o'qish va CSV tahlili.

🕑 12 daqiqa o‘qish 📄 816 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Path va Files
  2. Matn yozish va o'qish
  3. Qatorlar bilan ishlash
  4. Oqim sifatida o'qish
  5. Kataloglar
  6. CSV o'qish
  7. Fayl xatolarini boshqarish
  8. Eski va yangi API
  9. Xulosa

Dastur ishini saqlab qolishi kerak. Java'da fayl bilan ishlashning zamonaviy usuli - java.nio.file paketi.

Path va Files #

Java
import java.nio.file.*;

public class Yollar {
    public static void main(String[] args) {
        Path yol = Path.of("hujjatlar", "hisobot", "2026-yil.txt");

        System.out.println("To'liq yo'l:  " + yol);
        System.out.println("Fayl nomi:    " + yol.getFileName());
        System.out.println("Papka:        " + yol.getParent());
        System.out.println("Qismlar soni: " + yol.getNameCount());
        System.out.println("Mutlaqmi:     " + yol.isAbsolute());
        System.out.println("Qo'shilgan:   " + yol.resolveSibling("eski.txt"));
    }
}
Natija
To'liq yo'l:  hujjatlar\hisobot\2026-yil.txt
Fayl nomi:    2026-yil.txt
Papka:        hujjatlar\hisobot
Qismlar soni: 3
Mutlaqmi:     false
Qo'shilgan:   hujjatlar\hisobot\eski.txt
Ajratuvchi tizimga bog'liq

Yuqoridagi chiqishda teskari chiziq (\) ko'rinadi, chunki misol Windows'da bajarildi. Linux va macOS'da xuddi shu kod to'g'ri chiziq (/) chiqaradi.

Aynan shuning uchun yo'llarni qo'lda birlashtirmang:

Java
String yomon = "hujjatlar" + "\\" + "fayl.txt";      // faqat Windows
Path yaxshi = Path.of("hujjatlar", "fayl.txt");      // hamma joyda

Path.of ishlayotgan tizimga mos ajratuvchini o'zi qo'yadi. Bu darslikdagi yagona misol bo'lib, uning natijasi tizimga bog'liq - qolgan hamma narsa hamma joyda bir xil.

Matn yozish va o'qish #

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class Matn {
    public static void main(String[] args) throws IOException {
        Path yol = Files.createTempFile("sinov", ".txt");

        Files.writeString(yol, "Birinchi qator\nIkkinchi qator",
                StandardCharsets.UTF_8);

        String matn = Files.readString(yol, StandardCharsets.UTF_8);
        System.out.println("Uzunligi: " + matn.length());
        System.out.println(matn);

        System.out.println("Mavjudmi: " + Files.exists(yol));
        Files.delete(yol);
        System.out.println("O'chirilgach: " + Files.exists(yol));
    }
}
Natija
Uzunligi: 29
Birinchi qator
Ikkinchi qator
Mavjudmi: true
O'chirilgach: false
Kodlashni har doim oshkora ko'rsating

Files.readString(yol) deb yozsangiz ham ishlaydi, lekin StandardCharsets.UTF_8 ni oshkora berish yaxshi odat.

Java 18 gacha sukut kodlash operatsion tizim sozlamasidan olinardi. Ya'ni Windows'da fayl windows-1251 da o'qilishi, Linux'da esa UTF-8 da o'qilishi mumkin edi - va o'zbek harflari buzilib chiqardi.

Java 18 dan sukut UTF-8 ga o'tdi, lekin:

  • eski Java versiyalarida kod boshqacha ishlaydi;
  • FileReader kabi eski sinflar hali ham tizim sozlamasiga tayanadi.

Qoida: fayl bilan ishlaganda kodlashni har doim yozing. Bu bir necha belgi qo'shimcha, lekin o'zbek matni bilan ishlaganda jiddiy muammodan saqlaydi.

Qatorlar bilan ishlash #

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;

public class Qatorlar {
    public static void main(String[] args) throws IOException {
        Path yol = Files.createTempFile("shaharlar", ".txt");

        Files.write(yol, List.of("Namangan", "Andijon", "Samarqand"),
                StandardCharsets.UTF_8);

        List<String> qatorlar =
                Files.readAllLines(yol, StandardCharsets.UTF_8);
        System.out.println(qatorlar.size() + " ta qator:");
        for (int i = 0; i < qatorlar.size(); i++) {
            System.out.println("  " + (i + 1) + ". " + qatorlar.get(i));
        }

        Files.writeString(yol, "Toshkent\n", StandardCharsets.UTF_8,
                StandardOpenOption.APPEND);
        System.out.println("Qo'shilgach: "
                + Files.readAllLines(yol, StandardCharsets.UTF_8).size()
                + " ta");

        Files.delete(yol);
    }
}
Natija
3 ta qator:
  1. Namangan
  2. Andijon
  3. Samarqand
Qo'shilgach: 4 ta
Files.writeString sukut bo'yicha ustiga yozadi

Qo'shish uchun StandardOpenOption.APPEND berish shart. Usiz mavjud mazmun butunlay almashtiriladi va hech qanday ogohlantirish bo'lmaydi.

Boshqa foydali variantlar:

VariantNima qiladi
CREATEYo'q bo'lsa yaratadi (sukut)
APPENDOxiriga qo'shadi
TRUNCATE_EXISTINGMavjudini tozalaydi (sukut)
CREATE_NEWFaqat yangi yaratadi, bor bo'lsa istisno

CREATE_NEW mavjud faylni tasodifan buzib qo'yishdan himoya qiladi.

Oqim sifatida o'qish #

Katta faylni butunlay xotiraga yuklamaslik uchun:

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.List;
import java.util.stream.Stream;

public class OqimBilan {
    public static void main(String[] args) throws IOException {
        Path yol = Files.createTempFile("ballar", ".txt");
        Files.write(yol, List.of("92", "78", "85", "", "95", "64"),
                StandardCharsets.UTF_8);

        try (Stream<String> qatorlar =
                     Files.lines(yol, StandardCharsets.UTF_8)) {
            var statistika = qatorlar
                    .filter(q -> !q.isBlank())
                    .mapToInt(Integer::parseInt)
                    .summaryStatistics();

            System.out.println("Soni:     " + statistika.getCount());
            System.out.println("Yig'indi: " + statistika.getSum());
            System.out.println("Eng past: " + statistika.getMin());
            System.out.println("Eng yuqori: " + statistika.getMax());
        }

        Files.delete(yol);
    }
}
Natija
Soni:     5
Yig'indi: 414
Eng past: 64
Eng yuqori: 95
Files.lines ni try-with-resources ichida ishlating

Files.lines ochiq fayl deskriptorini ushlab turadi va u AutoCloseable. Uni yopmasangiz, fayl ochiq qoladi.

Bitta faylda bu sezilmaydi. Lekin minglab faylni qayta ishlaydigan dasturda tizim chegarasi tugaydi:

Natija
java.nio.file.FileSystemException: Too many open files

Files.readAllLines esa faylni to'liq o'qib, darhol yopadi - unda bu muammo yo'q, lekin katta fayl xotirani to'ldiradi.

Qoida: kichik fayl - readAllLines, katta fayl - try (Stream<String> ...).

Kataloglar #

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.stream.Stream;

public class Kataloglar {
    public static void main(String[] args) throws IOException {
        Path asos = Files.createTempDirectory("sinov");
        Path ichki = asos.resolve("ichki");
        Files.createDirectories(ichki);

        Files.writeString(asos.resolve("a.txt"), "a", StandardCharsets.UTF_8);
        Files.writeString(asos.resolve("b.txt"), "bb",
                StandardCharsets.UTF_8);
        Files.writeString(ichki.resolve("c.txt"), "ccc",
                StandardCharsets.UTF_8);

        try (Stream<Path> yuza = Files.list(asos)) {
            System.out.println("Faqat asosda: " + yuza.count() + " ta");
        }

        try (Stream<Path> chuqur = Files.walk(asos)) {
            long fayllar = chuqur.filter(Files::isRegularFile).count();
            System.out.println("Barcha fayllar: " + fayllar + " ta");
        }

        System.out.println("a.txt hajmi: "
                + Files.size(asos.resolve("a.txt")) + " bayt");
        System.out.println("Katalogmi: " + Files.isDirectory(ichki));

        ochir(asos);
        System.out.println("O'chirilgach mavjudmi: " + Files.exists(asos));
    }

    static void ochir(Path yol) throws IOException {
        try (Stream<Path> hammasi = Files.walk(yol)) {
            for (Path p : hammasi.sorted((a, b) -> b.compareTo(a)).toList()) {
                Files.delete(p);
            }
        }
    }
}
Natija
Faqat asosda: 3 ta
Barcha fayllar: 3 ta
a.txt hajmi: 1 bayt
Katalogmi: true
O'chirilgach mavjudmi: false
Katalogni o'chirish uchun alohida kod kerak

Files.delete faqat bo'sh katalogni o'chiradi. To'la katalogni o'chirish uchun avval ichidagilarni tozalash kerak.

Yuqoridagi ochir metodi buni teskari tartibda saralab hal qiladi: Files.walk yuqoridan pastga yuradi, teskari saralash esa eng chuqur fayllarni birinchi qo'yadi. Shunda har bir katalog o'chirilayotganda allaqachon bo'sh bo'ladi.

Diqqat: bu kod haqiqiy loyihada xavfli - noto'g'ri yo'l berilsa ko'p narsani o'chirib yuborishi mumkin. Amalda tayyor kutubxona ishlating.

CSV o'qish #

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;

public class Csv {
    public static void main(String[] args) throws IOException {
        Path yol = Files.createTempFile("jurnal", ".csv");
        Files.write(yol, List.of(
                "ism,ball,guruh",
                "Husanboy,92,A",
                "Malika,78,B",
                "Nodira,85,A"), StandardCharsets.UTF_8);

        List<Talaba> talabalar;
        try (Stream<String> qatorlar =
                     Files.lines(yol, StandardCharsets.UTF_8)) {
            talabalar = qatorlar
                    .skip(1)
                    .map(q -> q.split(","))
                    .map(q -> new Talaba(q[0], Integer.parseInt(q[1]), q[2]))
                    .toList();
        }

        talabalar.forEach(System.out::println);

        Map<String, Double> ortacha = talabalar.stream()
                .collect(Collectors.groupingBy(Talaba::guruh, TreeMap::new,
                        Collectors.averagingInt(Talaba::ball)));
        System.out.println("Guruh o'rtachasi: " + ortacha);

        Files.delete(yol);
    }
}

record Talaba(String ism, int ball, String guruh) {
}
Natija
Talaba[ism=Husanboy, ball=92, guruh=A]
Talaba[ism=Malika, ball=78, guruh=B]
Talaba[ism=Nodira, ball=85, guruh=A]
Guruh o'rtachasi: {A=88.5, B=78.0}
Haqiqiy CSV split(",") dan murakkabroq

Yuqoridagi kod oddiy holatda ishlaydi, lekin haqiqiy CSV fayllarda:

  • qiymat ichida vergul bo'lishi mumkin: "Qodirov, Husanboy";
  • qo'shtirnoq ichida yangi qator bo'lishi mumkin;
  • qo'shtirnoqning o'zi ikkilantirilib yoziladi: "".

Bunday fayllarni split(",") bilan o'qish buzilgan ma'lumot beradi - va bu jimgina sodir bo'ladi.

Jiddiy ishda tayyor kutubxona ishlating (masalan Apache Commons CSV yoki OpenCSV). Bu darslikdagi misol faqat oqim bilan ishlashni ko'rsatish uchun.

Fayl xatolarini boshqarish #

Java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class Xatolar {
    public static void main(String[] args) {
        Path yoq = Path.of("bunday-fayl-yoq-12345.txt");

        try {
            Files.readString(yoq, StandardCharsets.UTF_8);
        } catch (NoSuchFileException x) {
            System.out.println("Fayl topilmadi: " + x.getFile());
        } catch (IOException x) {
            System.out.println("Kirish-chiqish xatosi: " + x.getMessage());
        }

        System.out.println("Mavjudmi: " + Files.exists(yoq));
        System.out.println("O'qish mumkinmi: " + Files.isReadable(yoq));
    }
}
Natija
Fayl topilmadi: bunday-fayl-yoq-12345.txt
Mavjudmi: false
O'qish mumkinmi: false
IOException ni oxiriga qo'ying

NoSuchFileException IOException dan meros oladi. Shuning uchun IOException ni yuqoriga qo'ysangiz, aniqroq turlar hech qachon ishlamaydi - va kompilyator bu haqda xato beradi (13-bo'lim).

Foydali maxsus turlar:

TurQachon
NoSuchFileExceptionFayl yo'q
FileAlreadyExistsExceptionCREATE_NEW da fayl bor
AccessDeniedExceptionRuxsat yo'q
DirectoryNotEmptyExceptionBo'sh bo'lmagan katalogni o'chirish

Eski va yangi API #

Eski (java.io)Yangi (java.nio.file)
FilePath
new FileReader(f)Files.readString
new FileWriter(f)Files.writeString
f.delete() - boolean qaytaradiFiles.delete - istisno tashlaydi
f.listFiles()Files.list
Nega yangi API afzal

Eng muhim farq - xato haqida xabar berish.

Eski File.delete() shunchaki false qaytaradi. Nega? Fayl yo'qmi, ruxsat yo'qmi, band'mi - bilib bo'lmaydi. Va ko'pchilik natijani umuman tekshirmaydi.

Files.delete() esa aniq istisno tashlaydi va sababini aytadi.

Yangi kodda har doim Path va Files ishlating. Eski File faqat eski kutubxonalar bilan ishlaganda kerak bo'ladi - bunday holatda file.toPath() va path.toFile() yordam beradi.

Amaliy topshiriq
  1. Path.of bilan yo'l yaratib, qismlarini chiqaring.
  2. Faylga matn yozing va qaytadan o'qing.
  3. Kodlashni oshkora ko'rsatmasdan o'zbekcha matn yozib ko'ring.
  4. APPEND bilan va usiz yozib, farqni ko'ring.
  5. Files.lines ni try-with-resources ichida ishlating.
  6. Katalog yaratib, ichida fayllar yarating va sanang.
  7. Files.walk bilan ichki fayllarni ham sanang.
  8. CSV faylni o'qib, record ro'yxatiga aylantiring.
  9. Mavjud bo'lmagan faylni o'qib, NoSuchFileException ni ushlang.
  10. IOException ni yuqoriga qo'yib, kompilyator nima deyishini ko'ring.

Xulosa #

  • Zamonaviy API - Path va Files, eski File emas.
  • Yo'llarni Path.of bilan quring - ajratuvchi tizimga bog'liq.
  • Fayl bilan ishlaganda kodlashni oshkora ko'rsating (StandardCharsets.UTF_8).
  • Files.writeString sukut bo'yicha ustiga yozadi - qo'shish uchun APPEND.
  • Kichik fayl uchun readAllLines, katta fayl uchun Files.lines va try-with-resources.
  • Files.delete faqat bo'sh katalogni o'chiradi.
  • split(",") bilan haqiqiy CSV o'qib bo'lmaydi - kutubxona ishlating.
  • catch da IOException ni oxiriga qo'ying.

Keyingi bo'limda kodni sinovdan o'tkazishni o'rganamiz.

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.