1. DataInputStream və DataOutputStream nə üçün lazımdır?
Fayllarla işləyərkən bəzən sırf mətn deyil, strukturlu məlumatları saxlamaq lazım olur: rəqəmlər, boolean dəyərlər, primitiv massivlər. Məsələn, sadə bir oyun yazdığınızı və istifadəçinin irəliləyişini saxlamaq istədiyinizi təsəvvür edin: xal sayı (int), cari səviyyə (int), oyun vaxtı (double), qalib statusu (boolean). Bunu əlbəttə mətn şəklində də yaza bilərsiniz:
12345
5
67.5
true
Amma bu, nə rahatdır, nə də təhlükəsizdir: sətirləri parse etmək lazımdır, format dəyişə və ya pozula bilər, həm də rəqəmlər daha çox yer tutur.
Fikir ondan ibarətdir ki, məlumatları fayla mətinə çevirmədən “xam” (ikili) şəkildə yazmaq. Bunun üçün Java-da iki əla sinif var:
- DataOutputStream — primitiv tipləri axına yaza bilir.
- DataInputStream — primitiv tipləri axından oxuya bilir.
Onlar adi bayt axınlarının (OutputStream/InputStream) üzərində işləyir. Yəni bunlar elə “üst qat”dır ki, təkcə bayt yazmırlar, həm də bu baytlardan int, double, boolean və hətta String yaratmağı bilirlər.
Bu necə işləyir?
Adi FileOutputStream-u elə bir konveyer kimi təsəvvür etmək olar ki, baytları bir-bir özünüz yerləşdirirsiniz. Tam ədəd və ya sətir yazmaq istəsəniz, hər elementin neçə bayt tutduğunu özünüz izləməlisiniz.
DataOutputStream işi asanlaşdırır: o, bu konveyerdə robot kimi davranır. Siz ona “rəqəmi yaz” və ya “sətiri yaz” deyirsiniz, o da məlumatları lazım olan sayda bayta qablaşdırıb diskə göndərir. Konveyerin digər ucunda həmin baytları geri orijinal obyektlərə yığmağı bacaran eyni cür robot — DataInputStream var.
Niyə bu rahatdır? Çünki int, double və ya boolean üçün neçə bayt lazım olduğunu düşünməyəcəksiniz. Məlumatlar yığcam saxlanır, sürətlə yazılıb oxunur və parse xətaları və ya format problemləri riski azalır.
2. Nümunə: primitivlərin yazılması və oxunması
Güman edək ki, (şərti) oyunumuzun nəticələrini saxlamaq istəyirik: oyunçunun adı (String), xal sayı (int), rekord vaxt (double), oyunçu qalib olubmu (boolean).
Məlumatların fayla yazılması
import java.io.*;
public class SaveGameData {
public static void main(String[] args) {
String fileName = "savegame.bin";
String playerName = "Alice";
int score = 12345;
double recordTime = 67.5;
boolean isWinner = true;
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream(fileName))) {
dos.writeUTF(playerName); // Sətiri yazırıq (UTF-8)
dos.writeInt(score); // int yazırıq (4 bayt)
dos.writeDouble(recordTime); // double yazırıq (8 bayt)
dos.writeBoolean(isWinner); // boolean yazırıq (1 bayt)
System.out.println("Məlumatlar fayla uğurla yazıldı!");
} catch (IOException e) {
System.out.println("Yazma xətası: " + e.getMessage());
}
}
}
- writeUTF(String) — sətiri UTF-8 formatında yazır (başda uzunluqla).
- writeInt(int) — 4 bayt yazır.
- writeDouble(double) — 8 bayt yazır.
- writeBoolean(boolean) — 1 bayt yazır (1 və ya 0).
- Bütün metodlar məlumatları lazım olan formata avtomatik “qablaşdırır”.
Fayldan məlumatların oxunması
import java.io.*;
public class LoadGameData {
public static void main(String[] args) {
String fileName = "savegame.bin";
try (DataInputStream dis = new DataInputStream(
new FileInputStream(fileName))) {
String playerName = dis.readUTF(); // Sətiri oxuyuruq
int score = dis.readInt(); // int oxuyuruq
double recordTime = dis.readDouble(); // double oxuyuruq
boolean isWinner = dis.readBoolean(); // boolean oxuyuruq
System.out.println("Oyunçunun adı: " + playerName);
System.out.println("Xallar: " + score);
System.out.println("Vaxt: " + recordTime);
System.out.println("Qalib: " + isWinner);
} catch (IOException e) {
System.out.println("Oxuma xətası: " + e.getMessage());
}
}
}
Vacib məqam:
Oxuma ardıcıllığı yazma ardıcıllığı ilə eyni olmalıdır! Əgər əvvəl sətir, sonra int, sonra double yazmısınızsa — eyni ardıcıllıqla oxuyun. Əks halda səhv və ya “qarışıq” məlumat alacaqsınız.
3. Hansı tiplər dəstəklənir?
DataOutputStream və DataInputStream Java-nın bütün əsas primitiv tiplərini dəstəkləyir:
| Yazma metodu | Oxuma metodu | Məlumat tipi | Ölçü (bayt) |
|---|---|---|---|
|
|
boolean | 1 |
|
|
byte | 1 |
|
|
short | 2 |
|
|
char | 2 |
|
|
int | 4 |
|
|
long | 8 |
|
|
float | 4 |
|
|
double | 8 |
|
|
String (UTF) | dəyişkən |
Qeydlər:
- Sətirlər üçün adətən writeUTF/readUTF istifadə olunur (başda sətirin uzunluğu və sonra UTF-8-də baytlar yazılır).
- Massivi yazmaq istəyirsinizsə, əvvəlcə onun uzunluğunu, sonra isə elementləri bir-bir yazın.
4. İrəliləmiş nümunə: primitiv massivləri saxlamaq
Massivin yazılması
int[] scores = {100, 200, 300, 400, 500};
try (DataOutputStream dos = new DataOutputStream(
new FileOutputStream("scores.bin"))) {
dos.writeInt(scores.length); // Əvvəlcə massivın uzunluğunu yazırıq
for (int score : scores) {
dos.writeInt(score); // Sonra isə hər elementi
}
}
Massivin oxunması
try (DataInputStream dis = new DataInputStream(
new FileInputStream("scores.bin"))) {
int length = dis.readInt(); // Uzunluğu oxuyuruq
int[] scores = new int[length];
for (int i = 0; i < length; i++) {
scores[i] = dis.readInt(); // Elementləri oxuyuruq
}
// Massivi çap edirik
for (int score : scores) {
System.out.println(score);
}
}
Niyə əvvəlcə uzunluq?
Çünki oxuyarkən neçə ədəd yazıldığını bilmirik. Başda uzunluğu yazmaqla fayl formatını özünü sənədləşdirən edirik.
5. Vacib nüanslar və xüsusiyyətlər
DataInputStream/DataOutputStream nə vaxt istifadə olunmalıdır?
- Primitivlərdən ibarət strukturlu məlumatları saxlamaq/yükləmək lazım olanda.
- Java-da yazılmış proqramlar arasında ikili məlumat mübadiləsi üçün (hətta formatı bilirsinizsə, müxtəlif dillər arasında da).
- Yığcamlıq və sürət vacib olanda (məsələn, loglar, hesablamaların nəticələri, böyük ədəd massivləri).
Nə vaxt istifadə etməmək lazımdır:
- Əgər insan üçün oxunaqlı format lazımdırsa (CSV, JSON, XML) — mətn formatlarından istifadə edin.
- Daxili qurulu mürəkkəb obyektlər üçün — ObjectOutputStream/ObjectInputStream vasitəsilə seriyalaşdırmadan istifadə etmək daha yaxşıdır (bu ayrıca mövzudur).
Bufferləşdirmə
DataOutputStream və DataInputStream öz-özlüyündə məlumatları bufferləşdirmir. Böyük fayllarla işləyərkən performansı artırmaq istəyirsinizsə, onları BufferedOutputStream/BufferedInputStream ilə qablaşdırın:
try (DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream("data.bin")))) {
// ...
}
Sətirlərin kodlaşdırılması
Metodlar writeUTF/readUTF xüsusi formatdan istifadə edir: əvvəlcə sətirin uzunluğu (baytlarda) yazılır, sonra isə məzmunu UTF-8-də. Bunu sadəcə bayt massivinin yazılması ilə qarışdırmayın!
İstisnalar
Oxuma/yazma əməliyyatları IOException ata bilər, əgər fayl əlçatan deyil, zədələnib və ya vaxtından əvvəl başa çatıbsa. Yazılandan artıq oxumağa cəhd etdikdə çox vaxt EOFException gəlir. Həmişə try-with-resources konstruksiyasından istifadə edin və ya istisnaları try-catch ilə emal edin.
Oxu və yazma ardıcıllığı
Ən yayğın səhv — oxuma və yazma ardıcıllığının uyğun gəlməməsidir. Əgər belə yazmısınızsa: int, double, boolean, amma oxuyursunuz: double, int, boolean — səhv məlumat və ya istisna alacaqsınız.
6. Tipik səhvlər
Xəta № 1: Yazma və oxuma ardıcıllığının pozulması. Metodların ardıcıllığını dəyişsəniz, məlumatlar səhv oxunacaq və ya istisna atılacaq. Məsələn, əvvəlcə sətir, sonra rəqəm yazmısınız, amma oxuyarkən əvvəlcə rəqəmi oxumağa cəhd edirsiniz — format xətası alacaqsınız.
Xəta № 2: Massivin uzunluğunu yazmağı unutmusunuz. Primitiv massivini yazırsınızsa, lakin onun uzunluğunu yazmamısınızsa, oxuyarkən neçə elementi oxumaq lazım olduğunu bilməyəcəksiniz. Bu ya səhvə, ya da sonda “artıq” məlumatların çıxmasına gətirib çıxarır.
Xəta № 3: Faylın sonundan sonra oxumağa cəhd. Yazılandan çox məlumat oxumağa çalışsanız, EOFException (end of file) alacaqsınız.
Xəta № 4: Mətn faylları üçün DataInputStream/DataOutputStream istifadə etmək. Bu siniflər, məsələn, Notepad-da yaradılmış adi mətn fayllarını oxumaq üçün nəzərdə tutulmayıb. Belə faylı readInt() ilə oxumağa çalışsanız — mənasız məlumat və ya səhv alacaqsınız.
Xəta № 5: Axını bağlamamısınız. Əgər try-with-resources istifadə etmirsinizsə və ya axınları əl ilə bağlamırsınızsa, fayl digər proqramlar üçün əlçatan olmaya bilər və ya dəyişikliklər tam yazılmaya bilər.
GO TO FULL VERSION