CodeGym /Kurslar /JAVA 25 SELF /Binar faylların oxunması və yazılması: InputStream, Outpu...

Binar faylların oxunması və yazılması: InputStream, OutputStream

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

1. Giriş

Gəlin ən sadəsindən başlayaq: binar fayl mətn faylından nə ilə fərqlənir? Mətn faylı — adi bloknotda açıb hərfləri, rəqəmləri, boşluqları və digər simvolları görə bildiyiniz fayldır. Məsələn, my_notes.txt və ya poem.txt.

Binar fayl — mətn deyil, ixtiyari baytlar saxlayan fayldır. Bu, şəkil (.jpg, .png), musiqi (.mp3), arxiv (.zip), icra oluna bilən fayl (.exe), video (.mp4), verilənlər bazası faylı və sair ola bilər. Belə faylı bloknotda açsanız, ÿØÿà kimi bir şey və ya anlaşılmaz simvollardan ibarət bütöv bir “divar” görərsiniz. Bu, normaldır! Kompüter yalnız baytları “anlayır” — onun üçün həm mətn, həm şəkil, həm də video sadəcə baytların ardıcıllığıdır. Mətn fayllarında bu baytları simvol kimi şərh etmək olar, binar fayllarda isə onlar insan tərəfindən oxunmaq üçün nəzərdə tutulmayan “xam” verilənlərdir.

Binar fayllarla işləmək üçün əsas siniflər

Java-da binar fayllarla işləmək üçün bayt axınlarından istifadə olunur:

  • InputStream — baytların oxunması üçün əsas sinif.
  • OutputStream — baytların yazılması üçün əsas sinif.

Fayllarla işləmək üçün onların konkret reallaşdırmaları var:

  • FileInputStream — fayldan baytları oxuyur.
  • FileOutputStream — fayla baytlar yazır.

Əgər FileReader və FileWriter haqqında eşitmisinizsə, bilin: onlar simvollarla işləyir və yalnız mətn üçün uyğundur. Binar fayllar üçün yalnız InputStream/OutputStream və onların törəmələrindən istifadə edin.

2. Binar faylların oxunması

Bayt-bayt oxuma

Ən sadə üsul — faylı bir-bir baytla oxumaqdır. Bu başadüşüləndir, lakin çox yavaşdır.

try (FileInputStream in = new FileInputStream("image.jpg")) {
    int b;
    while ((b = in.read()) != -1) {
        // b — 0-dan 255-ə qədər ədəd (bayt), -1 faylın sonu deməkdir
        // Baytı emal etmək olar, məsələn, bütün baytların cəmini hesablamaq
    }
}

Metod read() növbəti baytı int kimi qaytarır (0-dan 255-ə qədər), fayl bitdikdə isə -1 qaytarır. Adətən bayt-bayt oxunuş yalnız çox spesifik ehtiyac olduqda istifadə olunur (məsələn, faylın strukturunu analiz etmək).

Bloklarla oxuma (buferlə)

Bayt-bayt oxumaq — hər almanı ayrıca almaq üçün mağazaya getməyə bənzəyir. Daha səmərəlisi bir dəfəyə bütöv paket götürməkdir! Java-da bunun üçün fayldan baytlarla massivi dolduran read(byte[] buffer) metodu var.

try (FileInputStream in = new FileInputStream("image.jpg")) {
    byte[] buffer = new byte[4096]; // 4 KB bufer
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1) {
        // buffer fayldan bytesRead sayda bayt ehtiva edir
        // Bu baytları emal etmək olar, məsələn, onları başqa yerə saxlamaq
    }
}

Metod read(buffer) həqiqətən neçə bayt oxunduğunu qaytarır (buferin ölçüsündən az ola bilər, xüsusilə son oxunuşda). Bu üsul daha sürətlidir, çünki diskə müraciətlərin sayı azdır.

Nümunə: faylın kopyalanması

Gəlin sadə bir proqram yazaq: istənilən binar faylı (məsələn, şəkli) bir yerdən digərinə kopyalayır.

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BinaryCopyExample {
    public static void main(String[] args) {
        String source = "cat.jpg";
        String dest = "cat_copy.jpg";

        try (FileInputStream in = new FileInputStream(source);
             FileOutputStream out = new FileOutputStream(dest)) {

            byte[] buffer = new byte[8192]; // 8 KB — əksər tapşırıqlar üçün optimal ölçüdür
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            System.out.println("Kopyalama başa çatdı!");
        } catch (IOException e) {
            System.out.println("Kopyalama zamanı səhv: " + e.getMessage());
        }
    }
}

Hər şey sadədir: mənbə fayldan blokları oxuyuruq və dərhal yeni fayla yazırıq. Bu üsul istənilən fayllarla işləyir: şəkillər, arxivlər, videolar.

3. Binar faylların yazılması

Bayt massivinin yazılması

Əgər bayt massiviniz varsa (məsələn, onu şəbəkədən almısınız və ya proqramda yaratmısınız), onu fayla belə yaza bilərsiniz:

byte[] data = new byte[] {1, 2, 3, 4, 5}; // nümunə massiv

try (FileOutputStream out = new FileOutputStream("data.bin")) {
    out.write(data); // bütün massivi fayla yazır
}

Metod write(byte[]) massivin bütün baytlarını yazır. Həmçinin yalnız bir hissəni yazmaq olar: out.write(data, offset, length).

Faylın hissə-hissə yazılması (məsələn, kopyalama zamanı)

Oxumada olduğu kimi, adətən buferdən istifadə olunur:

try (FileInputStream in = new FileInputStream("source.bin");
     FileOutputStream out = new FileOutputStream("dest.bin")) {

    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1) {
        out.write(buffer, 0, bytesRead);
    }
}

Burada fayldan oxuduğumuz hər şeyi dərhal digər fayla yazırıq. Belə kod çox vaxt arxivatorlarda, yükləyicilərdə, şəkil emal edən proqramlarda və s. rast gəlinir.

4. Faydalı nüanslar

Niyə binar fayllar üçün Reader/Writer istifadə etmək olmaz?

Reader və Writer baytlarla deyil, simvollarla (char) işləyir. Onlar kodlamaya (məsələn, UTF-8) uyğun olaraq baytları avtomatik simvollara çevirirlər. Bu, mətn üçün rahatdır, lakin binar fayllar üçün son dərəcə təhlükəlidir!

Əgər şəkli FileWriter vasitəsilə yazmağa çalışsanız, açıla bilməyən, korlanmış fayl alacaqsınız. Yadda saxlayın: hər hansı qeyri-mətn faylları üçün yalnız InputStream/OutputStream istifadə edin!

Binar fayllarla işləmənin vacib fərqləri və nüansları

  • Buferin ölçüsü: Çox kiçik bufer işi yavaşıdacaq (diskə həddən artıq müraciət), çox böyük bufer isə artıq yaddaş tutacaq. 4–16 KB adətən optimaldır.
  • Səhvlərin emalı: Həmişə IOException emal edin — fayl mövcud olmaya bilər, bloklana bilər və ya diskdə yer bitə bilər.
  • Axınların bağlanması: try-with-resources istifadə edin — bu, səhvlər olsa belə faylların bağlanmasını təmin edir.
  • Faylın üzərinə yazma: Əgər faylı new FileOutputStream("file.bin") ilə açsanız, onun üzərinə yazılacaq. Sona əlavə etmək üçün append = true parametrli konstruktordan istifadə edin.
  • Giriş hüquqları: Proqram faylı aça bilmirsə, oxuma/yazma hüquqlarını yoxlayın.
  • readAllBytes(): Bütün faylı bir sətirdə bayt massivinə oxumağa imkan verir. Böyük fayllar üçün istifadə etməyin ki, bütün yaddaşı “yeməsin”!

5. Binar fayllarla işləyərkən tipik səhvlər

Səhv №1: Binar fayllar üçün FileReader/FileWriter istifadə etmək. Bu, verilənlərin korlanmasına səbəb olacaq, çünki bu siniflər baytları simvollara və əksinə çevirir; şəkillər, arxivlər və s. üçün bu — fəlakətdir.

Səhv №2: read() metodunun qaytardığı dəyəri nəzərə almamaq. Metod read(byte[]) istədiyinizdən daha az bayt oxuya bilər, xüsusilə son blokda. Həmişə qaytarılan dəyəri istifadə edin ki, həqiqətən neçə baytın emal olunduğunu bilin.

Səhv №3: Axını bağlamağı unutmaq. Faylı bağlamasanız, o, bloklanmış qala bilər və məlumatlar sonadək yazılmaya bilər (xüsusilə yazma zamanı!). try-with-resources istifadə edin.

Səhv №4: Faylı ölçüsünü nəzərə almadan bütövlükdə yaddaşa oxumağa cəhd. Böyük fayllar üçün bu, OutOfMemoryError-a gətirib çıxaracaq. Buferdən istifadə edin və hissə-hissə oxuyun.

Səhv №5: İstisnaların emal edilməməsi. Fayllarla iş həmişə xətalara səbəb ola bilər: fayl tapılmadı, hüquqlar yoxdur, disk doludur. IOException emal etməyi unutmayın.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
İkili axından dəyərli fraqmentin çıxarılması 🧪
İkili axından dəyərli fraqmentin çıxarılması 🧪
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Artefaktın enerji potensialının hesablanması ⚛️
Artefaktın enerji potensialının hesablanması ⚛️
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION