Dosya İşlemleri ve I/O
Şimdiye kadar veriler programın içinde, bellekte yaşadı. Ama gerçek uygulamalar dış dünyayla konuşur: dosya okur/yazar, ağdan veri alır, kayıt tutar. Bu bölümde Java'da girdi/çıktı (I/O) işlemlerini, hem klasik akış (…
Dosya İşlemleri ve I/O
Şimdiye kadar veriler programın içinde, bellekte yaşadı. Ama gerçek uygulamalar dış dünyayla konuşur: dosya okur/yazar, ağdan veri alır, kayıt tutar. Bu bölümde Java'da girdi/çıktı (I/O) işlemlerini, hem klasik akış (stream) yaklaşımını hem de modern ve çok daha kısa olan NIO.2 API'sini öğreniyoruz.
Bu bölümün örnekleri repo klasörünü kirletmemek için geçici dosyalar (
Files.createTempFile) kullanır ve iş bitince onları siler. Kendi projelerinde elbette kalıcı yollar kullanırsın.
Klasik I/O: akışlar (streams)
Java'nın orijinal I/O modeli akışlar üzerine kuruludur: veriyi byte byte veya karakter karakter okuyup yazarsın. Verimlilik için bunları tamponlu (buffered) sarmalayıcılarla kullanırız:
- Yazma:
FileWriter→BufferedWriter(write,newLine) - Okuma:
FileReader→BufferedReader(readLine)
try (BufferedWriter w = new BufferedWriter(new FileWriter(dosya))) { w.write("satır"); w.newLine(); } try (BufferedReader r = new BufferedReader(new FileReader(dosya))) { String satir; while ((satir = r.readLine()) != null) { ... } }
Dikkat: akışlar birer kaynaktır ve mutlaka kapatılmalıdır. try-with-resources bunu otomatik
yapar (blok bitince close() + tampon boşaltma). Örnek 1 (./Ornek1.java) tamponlu yazma ve
satır satır okumayı gösterir.
Modern I/O: NIO.2 (Path ve Files)
Java 7 ile gelen java.nio.file paketi, sık yapılan işleri tek satıra indirir. Path bir
dosya yolunu temsil eder; Files ise yüksek seviyeli yardımcı metotlar sunar:
Files.write(path, List.of("a", "b", "c")); // listeyi satır satır yaz List<String> satirlar = Files.readAllLines(path); // tümünü oku Files.writeString(path, "ek\n", StandardOpenOption.APPEND); // sona ekle Files.exists(path); Files.size(path); Files.delete(path);
Path ayrıca yol parçalarıyla çalışmayı kolaylaştırır (getFileName, getParent). Örnek 2
(./Ornek2.java) NIO ile yazma/okuma/ekleme ve dosya bilgisi almayı gösterir.
Küçük dosyalarda
readAllLinespratiktir; çok büyük dosyalarda ise tümünü belleğe almak yerine satır satır akıtanFiles.lines(...)tercih edilir.
Files.lines + Stream
Files.lines(path) bir Stream<String> döndürür; böylece dosyayı satır satır, tembel biçimde
ve Stream API'nin tüm gücüyle işleyebilirsin. Bu stream bir kaynak tuttuğundan
try-with-resources içinde kullanılmalıdır:
try (Stream<String> satirlar = Files.lines(path)) { satirlar.filter(s -> s.startsWith("ERROR")).forEach(System.out::println); }
Örnek 3 (./Ornek3.java) küçük bir log dosyası oluşturur, seviyelere (INFO/WARN/ERROR)
göre kaç kayıt olduğunu groupingBy ile sayar ve yalnızca hata satırlarını süzer — dosya
işleme ile Stream API'yi bir araya getirir.
byte vs karakter akışları
İki tür akış vardır: byte akışları (InputStream/OutputStream) her tür ikili veri
(resim, ses, zip) için; karakter akışları (Reader/Writer) metin için kullanılır.
Metinle çalışırken karakter akışlarını (veya NIO'nun metin metotlarını) tercih edersin;
böylece karakter kodlaması (UTF-8 gibi) doğru ele alınır.
Özet
Klasik tamponlu akışlarla dosya okuyup yazmayı, modern NIO.2 (Path/Files) ile aynı işleri
çok daha kısa yapmayı ve Files.lines ile dosyaları Stream halinde işlemeyi öğrendik.
try-with-resources ile kaynakları güvenle kapattık. Sırada, programları aynı anda birden
çok iş yapabilir hale getiren konu: çoklu iş parçacığı ve eşzamanlılık.
▶ Kod Örnekleri(3)
Ornek1
çalıştırılabilir1// Ornek1: Klasik I/O — BufferedWriter ile yazma, BufferedReader ile okuma.
2// Çalıştırma: java Ornek1.java
3import java.io.BufferedReader;
4import java.io.BufferedWriter;
5import java.io.FileReader;
6import java.io.FileWriter;
7import java.io.IOException;
8import java.nio.file.Files;
9import java.nio.file.Path;
10
11public class Ornek1 {
12
13 public static void main(String[] args) throws IOException {
14 // Geçici dosya kullanıyoruz; repo klasörünü kirletmemek için.
15 Path dosya = Files.createTempFile("ornek-io-", ".txt");
16 System.out.println("Geçici dosya: " + dosya);
17
18 // --- Yazma ---
19 // try-with-resources: akış blok bitince otomatik kapanır (flush + close).
20 try (BufferedWriter yazici = new BufferedWriter(new FileWriter(dosya.toFile()))) {
21 yazici.write("Birinci satır");
22 yazici.newLine();
23 yazici.write("İkinci satır");
24 yazici.newLine();
25 yazici.write("Üçüncü satır");
26 yazici.newLine();
27 }
28 System.out.println("Dosyaya 3 satır yazıldı.");
29
30 // --- Okuma ---
31 System.out.println("\nDosya içeriği:");
32 int satirNo = 0;
33 try (BufferedReader okuyucu = new BufferedReader(new FileReader(dosya.toFile()))) {
34 String satir;
35 while ((satir = okuyucu.readLine()) != null) { // satır kalmayınca null döner
36 satirNo++;
37 System.out.println(" " + satirNo + ": " + satir);
38 }
39 }
40
41 // Temizlik
42 Files.deleteIfExists(dosya);
43 System.out.println("\nGeçici dosya silindi.");
44 }
45}Ornek2
çalıştırılabilir1// Ornek2: Modern NIO.2 — Path ve Files ile kısa dosya işlemleri.
2// Çalıştırma: java Ornek2.java
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6import java.util.List;
7
8public class Ornek2 {
9
10 public static void main(String[] args) throws IOException {
11 Path dosya = Files.createTempFile("ornek-nio-", ".txt");
12 System.out.println("Geçici dosya: " + dosya.getFileName());
13
14 // NIO ile yazma: tek satırda tüm listeyi yaz.
15 List<String> satirlar = List.of("elma", "armut", "kiraz", "muz");
16 Files.write(dosya, satirlar);
17 System.out.println("Yazılan satır sayısı: " + satirlar.size());
18
19 // NIO ile okuma: tüm satırları tek seferde listeye al.
20 List<String> okunan = Files.readAllLines(dosya);
21 System.out.println("Okunan: " + okunan);
22
23 // Sona ekleme (append)
24 Files.writeString(dosya, "çilek\n", java.nio.file.StandardOpenOption.APPEND);
25 System.out.println("Ekleme sonrası satır sayısı: " + Files.readAllLines(dosya).size());
26
27 // Dosya bilgileri
28 System.out.println("\nVar mı? : " + Files.exists(dosya));
29 System.out.println("Boyut (byte): " + Files.size(dosya));
30
31 // Path ile yol işlemleri (dosya oluşturmadan, sadece metin üzerinde)
32 Path ornekYol = Path.of("/home/kullanici/belgeler/rapor.pdf");
33 System.out.println("\nPath örneği: " + ornekYol);
34 System.out.println(" dosya adı : " + ornekYol.getFileName());
35 System.out.println(" üst dizin : " + ornekYol.getParent());
36
37 Files.deleteIfExists(dosya);
38 System.out.println("\nGeçici dosya silindi.");
39 }
40}Ornek3
çalıştırılabilir1// Ornek3: Log dosyası yazma ve Files.lines + Stream ile analiz.
2// Çalıştırma: java Ornek3.java
3import java.io.IOException;
4import java.nio.file.Files;
5import java.nio.file.Path;
6import java.util.List;
7import java.util.Map;
8import java.util.stream.Collectors;
9import java.util.stream.Stream;
10
11public class Ornek3 {
12
13 public static void main(String[] args) throws IOException {
14 Path log = Files.createTempFile("ornek-log-", ".log");
15
16 // Basit bir log dosyası oluştur (seviye + mesaj).
17 List<String> kayitlar = List.of(
18 "INFO uygulama başladı",
19 "WARN bellek %80",
20 "INFO istek alındı",
21 "ERROR veritabanı bağlantısı koptu",
22 "INFO istek tamamlandı",
23 "ERROR zaman aşımı",
24 "WARN yavaş sorgu"
25 );
26 Files.write(log, kayitlar);
27 System.out.println("Log dosyası yazıldı (" + kayitlar.size() + " kayıt).\n");
28
29 // Files.lines bir Stream<String> döndürür; try-with-resources ile kapatılmalı.
30 // Seviyelere göre kaç kayıt var?
31 try (Stream<String> satirlar = Files.lines(log)) {
32 Map<String, Long> seviyeSayisi = satirlar
33 .map(s -> s.split("\\s+")[0]) // ilk kelime = seviye
34 .collect(Collectors.groupingBy(s -> s, Collectors.counting()));
35 System.out.println("Seviye dağılımı: " + seviyeSayisi);
36 }
37
38 // Sadece ERROR satırlarını süz.
39 try (Stream<String> satirlar = Files.lines(log)) {
40 System.out.println("\nHata kayıtları:");
41 satirlar.filter(s -> s.startsWith("ERROR"))
42 .forEach(s -> System.out.println(" " + s));
43 }
44
45 Files.deleteIfExists(log);
46 System.out.println("\nGeçici log dosyası silindi.");
47 }
48}