CodeGym /Kurslar /JAVA 25 SELF /NIO2: Files, Paths, Files.walk: fayl sisteminin gəzilməsi...

NIO2: Files, Paths, Files.walk: fayl sisteminin gəzilməsi

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. NIO2: daha ətraflı tanışlıq

Artıq NIO2 ilə tanış olmuşuq, indi isə fayllar və qovluqlarla işləmək üçün bu faydalı kitabxana barədə biliklərimizi təkrar edib dərinləşdirəcəyik.

Əvvəllər Java-da yalnız File sinfi var idi. O, faylın mövcudluğunu yoxlamaq, fayl və qovluq yaratmaq və silmək, qovluqdakı faylların siyahısını almaq kimi işləri bacarırdı. Amma çox məhdudiyyətləri vardı:

  • yollarla işləmək əlverişli deyildi, xüsusən də müxtəlif əməliyyat sistemlərini nəzərə almaq lazım olanda (C:\Users\user\file.txt Windows-da və /home/user/file.txt Linux-da);
  • simvolik keçidlər, giriş hüquqları və fayl atributları üçün normal dəstək yox idi;
  • qovluq ağacının gəzilməsi imkanları məhdud idi;
  • xətaların emalı kifayət qədər zəif idi.

Java 7-də NIO2 (New Input/Output, versiya 2) meydana çıxanda, tərtibatçıların işi daha asan və rahat oldu. İndi bizim ixtiyarımızda bunlar var:

  • fayl və qovluq yolları ilə rahat işləmək üçün Path sinfi;
  • bütün əsas əməliyyatları təmin edən Files sinfi: oxuma, yazma, kopyalama, silmə, fayllar barədə məlumatların əldə edilməsi;
  • FileVisitor interfeysi və Files.walk kimi metodlar ki, fayl sistemini asan və çevik şəkildə gəzməyə imkan verir.

Niyə bu vacibdir?

  • Çoxplatformalılıq: Eyni kod Windows, Linux, macOS üzərində işləyir, ayırıcılara (/ və ya \) görə narahat olmadan.
  • Təhlükəsizlik və rahatlıq: Xətalar barədə daha çox informasiya, daha az “sehr” və gözlənilməz sürprizlər.
  • Güclü imkanlar: Nəhəng qovluqları emal etmək, hətta filtrləmə və paralel emalla rekursiv gəzinti etmək mümkündür.

2. Əsas siniflər: Path və Files

Sinif Path

Path — fayl və ya qovluğa aparan yolun müasir təqdimatıdır. O, mütləq real mövcud fayla işarə etmir — sadəcə üzərində rahat işləmək üçün bir yoldur.

Path əldə etmək

import java.nio.file.Path;
import java.nio.file.Paths;

Path path1 = Paths.get("file.txt"); // nisbi yol
Path path2 = Paths.get("/home/user/file.txt"); // mütləq yol
Path path3 = Path.of("mydir", "subdir", "file.txt"); // Java 11+ ilə

Fakt: Path əməliyyat sistemindən asılı deyil. / və ya \ ilə sətirləri əl ilə birləşdirməyi unudun!

Sətirə çevirmək

System.out.println(path1.toString());

Valideyn qovluğu və fayl adını almaq

Path parent = path1.getParent(); // nisbi yollar üçün null ola bilər
Path fileName = path1.getFileName(); // yalnız fayl adı

Sinif Files

Files — fayl və qovluqlarla bağlı bütün əməliyyatlar üçün statik metodların toplusudur:

  • Mövcudluğu yoxlama: Files.exists(path)
  • Faylların oxunması və yazılması: Files.readAllBytes(path), Files.write(path, bytes)
  • Məlumatların əldə edilməsi: Files.size(path), Files.getLastModifiedTime(path)
  • Kopyalama, silmə, köçürmə: Files.copy, Files.delete, Files.move

Nümunələr:

import java.nio.file.Files;
import java.nio.file.Path;

Path path = Path.of("file.txt");
if (Files.exists(path)) {
    System.out.println("Fayl mövcuddur!");
    System.out.println("Ölçü: " + Files.size(path) + " bayt");
    System.out.println("Son dəyişiklik: " + Files.getLastModifiedTime(path));
} else {
    System.out.println("Fayl tapılmadı.");
}

3. Fayl sisteminin gəzilməsi: Files.walk və “dostları”

Köhnə yanaşmanın problemi

Köhnə API-də kataloq və onun alt qovluqlarındakı bütün faylları gəzmək üçün rekursiv funksiyalar yazmaq, fayl ilə qovluğu əl ilə ayırd etmək və sonsuz rekursiyaya düşməmək üçün diqqətli olmaq lazım idi. Bu, təkcə yorucu deyildi, həm də səhv etmək çox asan idi.

Müasir üsul: Files.walk

Files.walk(Path start) Stream<Path> qaytarır — göstərilən yoldan başlayaraq bütün alt qovluqlar daxil olmaqla, fayl və qovluqların hamısının axını. İndi fayl sistemini gəzmək — bu sadəcə Axınlarla (Streams) işləməkdir!

Nümunə: Bütün faylları və qovluqları çıxarmaq

import java.nio.file.*;

try (var paths = Files.walk(Path.of("mydir"))) {
    paths.forEach(System.out::println);
}

Burada mydir qovluğundan başlayaraq bütün yollar (həm fayllar, həm də qovluqlar) çıxarılacaq.

Nümunə: Yalnız fayllar (qovluqlar olmadan)

try (var paths = Files.walk(Path.of("mydir"))) {
    paths.filter(Files::isRegularFile)
         .forEach(System.out::println);
}

Files.isRegularFile(path) metodu yalnız adi fayllar üçün true qaytarır (qovluq və ya simvolik keçid deyil).

Nümunə: Faylları uzantıya görə axtarmaq

Tutaq ki, kataloq və alt qovluqlarda bütün .txt fayllarını tapmaq lazımdır:

try (var paths = Files.walk(Path.of("mydir"))) {
    paths.filter(Files::isRegularFile)
         .filter(path -> path.toString().endsWith(".txt"))
         .forEach(System.out::println);
}

Nümunə: Bütün faylların ümumi ölçüsünü hesablayın

long totalSize = 0;
try (var paths = Files.walk(Path.of("mydir"))) {
    totalSize = paths.filter(Files::isRegularFile)
                     .mapToLong(path -> {
                         try {
                             return Files.size(path);
                         } catch (Exception e) {
                             System.err.println("Ölçünü oxuma xətası: " + path);
                             return 0L;
                         }
                     })
                     .sum();
}
System.out.println("Faylların ümumi ölçüsü: " + totalSize + " bayt");

Vacibdir!

  • Files.walk metodu bağlanmalı olan bir axın qaytarır (AutoCloseable reallaşdırır). Buna görə də try-with-resources istifadə edirik!
  • Susmaya görə gəzinti dərinliyi ən dərin səviyyəyədəkdir (bütün alt qovluqlar). Dərinliyi məhdudlaşdıra bilərsiniz: Files.walk(path, maxDepth)

4. Praktiki tapşırıqlar

Tapşırıq 1: Kataloqda bütün şəkilləri tapın

.jpg, .png, .gif uzantılı bütün faylları images qovluğunda tapıb adlarını çıxarmaq lazımdır.

import java.nio.file.*;
import java.util.Set;

Set<String> extensions = Set.of(".jpg", ".png", ".gif");

try (var paths = Files.walk(Path.of("images"))) {
    paths.filter(Files::isRegularFile)
         .filter(path -> {
             String name = path.getFileName().toString().toLowerCase();
             return extensions.stream().anyMatch(name::endsWith);
         })
         .forEach(System.out::println);
}

Tapşırıq 2: Bütün .txt fayllarını başqa qovluğa kopyalayın

import java.nio.file.*;

Path sourceDir = Path.of("src");
Path destDir = Path.of("dest");

try (var paths = Files.walk(sourceDir)) {
    paths.filter(Files::isRegularFile)
         .filter(path -> path.toString().endsWith(".txt"))
         .forEach(path -> {
             try {
                 Path relative = sourceDir.relativize(path);
                 Path target = destDir.resolve(relative);
                 Files.createDirectories(target.getParent());
                 Files.copy(path, target, StandardCopyOption.REPLACE_EXISTING);
                 System.out.println("Kopyalandı: " + path + " -> " + target);
             } catch (Exception e) {
                 System.err.println("Kopyalama xətası: " + path);
             }
         });
}

Burada alt qovluqların strukturu saxlanılır.

5. Faydalı nüanslar

NIO2 üstünlükləri

Çoxplatformalılıq

Path qovluq ayırıcılardan özü baş çıxarır. Kodunuz Windows, Linux, macOS üzərində eyni cür işləyəcək.

Axınlarla emal

Files.walk kimi metodlar (Stream<Path>) qaytarır; bu axını filtrasiya edə, çevirdə, kolleksiyalara toplaya bilərsiniz — Stream API nə bacarırsa.

Böyük qovluqlarla işləmək

Köhnə API fayl sayı çox olanda (məsələn, 100 000 şəkil) çökə bilərdi. NIO2 belə halları asanlıqla emal edir, çünki hər şeyi dərhal yaddaşa yükləmir.

Simvolik keçidlər, atributlar, giriş hüquqları

Yolun simvolik keçid olub-olmadığını öyrənmək (Files.isSymbolicLink(path)), POSIX icazələrini almaq (Files.getPosixFilePermissions(path)), fayl sahibini bilmək və daha çoxunu etmək mümkündür.

Köhnə və yeni API-nin müqayisəsi

Əməliyyat Köhnə API (File) Yeni API (Path, Files)
Mövcudluğu yoxlamaq
file.exists()
Files.exists(path)
Ölçünü almaq
file.length()
Files.size(path)
Qovluqdakı faylların siyahısı
file.listFiles()
Files.list(path)
Rekursiv gəzinti Rekursiya əl ilə
Files.walk(path)
Faylın kopyalanması file.renameTo() (etibarsız)
Files.copy(src, dest)
Uzantını almaq Sətiri parse etmək
path.getFileName().toString()
Valideyn qovluğunu almaq
file.getParentFile()
path.getParent()
Hüquqlarla iş Demək olar ki, yox
Files.getPosixFilePermissions(path)

Vacib xüsusiyyətlər

Fayl tipinin yoxlanması

  • Files.isRegularFile(path) — adi fayl
  • Files.isDirectory(path) — qovluq
  • Files.isSymbolicLink(path) — simvolik keçid

Böyük qovluqlarla iş

  • Bütün yolları siyahıda toplamaq lazım deyil: Stream<Path> ilə işləyin və gələn kimi emal edin.
  • İş bitdikdən sonra axın mütləq bağlanmalıdır (try-with-resources).

İstisnalar

  • Demək olar ki, bütün metodlar IOException ata bilər — xətaları emal etməyi (və ya yuxarı atmağı) unutmayın.

Gəzintinin dərinliyinin məhdudlaşdırılması

try (var paths = Files.walk(Path.of("mydir"), 2)) { // cəmi 2 səviyyə
    // ...
}

6. NIO2 ilə işləyərkən tipik səhvlər

Səhv №1: Files.walk axınını bağlamağı unutmaq. Əgər try-with-resources istifadə etməsəniz, resurs sızması baş verə bilər — fayl sistemi axını açıq qalacaq. Həmişə try (var paths = Files.walk(...)) { ... } konstruktsiyasından istifadə edin.

Səhv №2: yolun qovluq olub-olmadığını yoxlamamaq. Files.walk metoduna qovluq əvəzinə fayl yolu versəniz, gözlənilməz davranış və ya xəta ala bilərsiniz.

Səhv №3: istisnaları emal etməmək. Demək olar ki, bütün NIO2 metodları IOException ata bilər. Bu xətaları diqqətsiz qoymayın — ən azı istifadəçiyə mesaj göstərin və ya jurnallaşdırın.

Səhv №4: yol ayırıcları ilə qarışıqlıq. Əgər yolları əl ilə / və ya \ vasitəsilə birləşdirirsinizsə, bunu etməyə dəyməz! Path.of(...) və ya resolve(...) istifadə edin — onlar özləri doğru şəkildə həll edəcəklər.

Səhv №5: çox böyük qovluğu “yadaşa” yığmağa cəhd. Fayl sayı çox olanda bütün yolları siyahıda toplamayın — Stream<Path> ilə işləyin və onları ardıcıl emal edin.

Səhv №6: çoxplatformalılığı unutmaq. Windows və ya Unix tərzində absolyut yolları hardkod etməyin. Pathresolve/relativize kimi əməliyyatlardan istifadə edin — onlar istənilən OS-də düzgün işləyəcək.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION