Bölüm 8: Giriş Çıkış İşlemleri
Giriş
Öğrenme Çıktıları
Girdi/çıktı akışını ve System.in, System.out, System.err akışlarını anlatmak; klavyeden Scanner ile okumak.
Metin ve ikili dosya farkını, ASCII, ISO-8859-9 ve UTF-8 kodlamalarını, bir sayının dosyada kaç bayt tuttuğunu hesaplamak.
File, Scanner, BufferedReader, PrintWriter, FileWriter ile metin dosyası işlemek; kaynakları try-with-resources ile kapatmak.
Bayt (InputStream/OutputStream) ve karakter (Reader/Writer) akışlarını, tamponlu ve sarmalayıcı akışları ayırt etmek.
Bayt, blok ve satır düzeyinde kopyalamak; RandomAccessFile ile istenen konuma atlamak.
Nesneleri serileştirmek (Serializable, transient); NIO tamponu, kanalı ve seçicisinin ne işe yaradığını açıklamak.
Akışlar
Akış (Stream)
- Akış (stream), veriyi bir kaynaktan bir hedefe sırayla, parça parça taşıyan yapıdır. Veri karakter, sayı veya ham bayt olabilir.
- Girdi akışı (input stream): verinin programa girdiği akış. Örnek:
System.in(klavye). - Çıktı akışı (output stream): verinin programdan çıktığı akış. Örnek:
System.out(ekran). - Benzetme: su borusu. Bir uçtan giren su öbür uçtan aynı sırayla çıkar; borunun öbür ucunda musluk mu depo mu olduğu programı ilgilendirmez.
Kaynak ister klavye, ister dosya, ister ağ olsun, program aynı read() / write() metotlarını kullanır. Java G/Ç (giriş/çıkış, I/O) kütüphanesinin gücü bu ortak arayüzdedir.
Akışlar
Klavye ve Ekran: Standart Akışlar
- Geçici veri işleme: klavye ve ekran verisi saklanmaz; program kapanınca kaybolur.
- Anında akış: kullanıcı yazdıkça girdi gelir, program yazdıkça ekranda görünür.
- Her Java programı açılırken üç hazır akış alır:
| Akış | Java nesnesi | Tipi |
|---|---|---|
| standart girdi | System.in | InputStream |
| standart çıktı | System.out | PrintStream |
| standart hata | System.err | PrintStream |
System.err da ekrana yazar ama ayrı bir kanaldır: çıktı bir dosyaya yönlendirilse bile (java Uygulama > sonuc.txt) hata mesajları ekranda kalır.Akışlar
İlk Örnek: Okuma ve Yazma
import java.util.Scanner; public class AkisOrnek { public static void main(String[] args) { // Giriş akışından veri okuma Scanner scanner = new Scanner(System.in); int kullaniciGirdisi = scanner.nextInt(); // Çıkış akışına veri yazma System.out.println("Merhaba, Dünya!"); System.out.println("Girdiğiniz sayı: " + kullaniciGirdisi); System.err.println("Bu satır hata akışına yazıldı."); } }
42 Merhaba, Dünya! Girdiğiniz sayı: 42 Bu satır hata akışına yazıldı.
new Scanner(System.in): klavye akışını okuyan bir tarayıcı oluşturur.Scanner,java.utilpaketindedir;importşarttır.nextInt()kullanıcı bir sayı yazıp Enter'a basana kadar bekler (bloklanır).System.out.printlnçıktı akışına bir satır yazar.System.err.printlnhata akışına yazar; çoğu IDE bu satırı kırmızı gösterir.- Kullanıcı sayı yerine
abcyazarsaInputMismatchExceptionfırlatılır.
Akışlar
Scanner ile Klavyeden Okuma: Adım Adım
Scanner nesnesi System.in akışına bağlanır. Klavye tamponu boş.
print (println değil) soruyu yazar; kullanıcı cevabı aynı satıra yazar.
Kullanıcı Ayşe Yılmaz yazıp Enter'a basar. nextLine() boşluk dâhil bütün satırı alır, satır sonunu (⏎) atar.
İkinci soru yazılır.
nextInt() rakamları okuyup int 19'a çevirir. Satır sonu (⏎) ise tamponda kalır.
Okunan değer artık sıradan bir int: 19 + 1 = 20.
Çıktı akışına satırlar yazılır.
String birleştirme: "Seneye " + 20 + " yaşındasın.".
close() tarayıcıyla birlikte System.in'i de kapatır; program içinde bundan sonra klavyeden okunamaz.
import java.util.Scanner; public class KonsolOkuma { public static void main(String[] args) { Scanner klavye = new Scanner(System.in); System.out.print("Adınız: "); String ad = klavye.nextLine(); System.out.print("Yaşınız: "); int yas = klavye.nextInt(); int seneye = yas + 1; System.out.println("Merhaba " + ad + "!"); System.out.println("Seneye " + seneye + " yaşındasın."); klavye.close(); } }
Dosyalar ve Kodlama
Dosyalar
- Dosya, veriyi diskte kalıcı olarak saklar: program kapansa, bilgisayar yeniden başlasa da veri durur (RAM'deki değişkenler ise kaybolur).
- Her dosyadaki veri sonuçta 0'lar ve 1'ler, yani bayt dizisidir. Farkı, bu baytların nasıl yorumlandığı yaratır.
- Metin dosyaları (text): baytlar bir karakter kodlamasına göre harflere çevrilir; insanlar okuyabilir.
- İkili dosyalar (binary): baytlar sayı, piksel, ses örneği, makine komutu gibi verilerdir; ancak onları bilen bir program anlamlandırır.
dosya.txt bir onaltılık (hex) düzenleyicide:
0000 4D 65 72 68 61 62 61 2C Merhaba, 0008 20 64 C3 BC 6E 79 61 21 d..nya!
Solda konum, ortada her baytın onaltılık değeri, sağda ASCII karşılığı. 4D = 77 = M. 15 harf 16 bayt tutar: ü UTF-8'de iki bayttır (C3 BC).
Dosyalar ve Kodlama
Dosya İşleme Süreçleri
| Adım | Ne olur? | Java'da |
|---|---|---|
| Oluşturma | Diskte yeni, boş bir dosya oluşturulur. | file.createNewFile(); yazmak için açmak da oluşturur |
| Açma | Var olan dosyaya bir akış bağlanır. | new FileInputStream(ad), new FileReader(ad), new Scanner(file) |
| Yazma | Veri dosyaya aktarılır. | write(), print(), println() |
| Okuma | Veri dosyadan programa alınır. | read(), readLine(), nextLine() |
| Kapatma | Tamponda kalan veri diske yazılır, işletim sistemi kaynağı bırakılır. | close() veya try-with-resources |
Kapatılmayan dosya hem veri kaybına (tamponda bekleyen baytlar yazılmaz) hem de kaynak sızıntısına yol açar: işletim sisteminin aynı anda açık tutabileceği dosya sayısı sınırlıdır.
Dosyalar ve Kodlama
İlk Dosya Programı
import java.io.*; public class IlkDosya { public static void main(String[] args) throws IOException { // Metin dosyasına yazma FileWriter writer = new FileWriter("dosya.txt"); writer.write("Merhaba, dünya!"); writer.close(); // İkili dosyaya bir byte yazma FileOutputStream cikis = new FileOutputStream("veri.dat"); cikis.write(127); cikis.close(); // İkili dosyadan okuma FileInputStream stream = new FileInputStream("veri.dat"); int veri = stream.read(); stream.close(); System.out.println("Okunan byte: " + veri); File metin = new File("dosya.txt"); System.out.println("dosya.txt: " + metin.length() + " byte"); } }
Okunan byte: 127 dosya.txt: 16 byte
Merhaba, dünya!
FileWriter: metin yazar.FileOutputStream: ham bayt yazar;write(127)tek bayt7F.read(): baytı 0–255 arasıintdöndürür.
Dosyalar ve Kodlama
Metin Dosyaları
- Metin dosyaları yazdırılabilir karakterler (harf, rakam, noktalama, boşluk, satır sonu) içerir.
- Not Defteri, VS Code gibi metin düzenleyicileriyle açılıp düzenlenebilir. Örnek: kaynak kodlar (
.java,.c),.txt,.csv,.html. - Karakter kümesi / kodlama (character set / encoding): her karakterin hangi sayıyla (baytlarla) saklanacağını belirleyen tablodur. Yazan ve okuyan aynı kodlamayı kullanmalıdır.
7 bit, 128 karakter: İngilizce harfler, rakamlar, noktalama, kontrol karakterleri.
8 bit, 256 karakter: Batı Avrupa (Latin-1). é, ü, ö, ç var; ş, ğ, ı yok.
8 bit, Latin-5: Türkçe sürüm. Latin-1'deki 6 harfin yerine ğ, Ğ, ı, İ, ş, Ş gelir.
Unicode'un evrensel kodlaması: tüm dünya dilleri, 1–4 bayt. Web'in ve Java 18+ sürümünün varsayılanı.
Dosyalar ve Kodlama
İkili Dosyalar
- Baytları karakter olarak değil, programın belirlediği biçimde (format) saklar: sayılar, pikseller, ses örnekleri, makine kodu.
- Bilgisayar (doğru program) için anlamlıdır; insanlar doğrudan okuyamaz.
- Örnekler: çalıştırılabilir dosyalar (
.exe, Java'nın.classdosyaları), görüntü (.png,.jpg), müzik (.mp3), video (.mp4), veri dosyaları (.dat). - Avantajı: daha küçük ve daha hızlı işlenir; sayıyı metne çevirmek gerekmez.
IlkDosya.class hex düzenleyicide (ilk 32 bayt):
0000 CA FE BA BE 00 00 00 41 .......A 0008 00 5C 0A 00 02 00 03 07 .\...... 0010 00 04 0C 00 05 00 06 01 ........ 0018 00 10 6A 61 76 61 2F 6C ..java/l
Aynı dosya Not Defteri ile açılınca:
Êþº¾···A·\················java/lang/Object···<init>···()V······java/io/FileWriter······dosya.txt·············(
Her .class dosyası CA FE BA BE baytlarıyla başlar: JVM dosyanın türünü bu “sihirli sayıdan” tanır.
Dosyalar ve Kodlama
Genişletilmiş ASCII ve Türkçe Karakterler
- Genişletilmiş ASCII (extended ASCII): 8 bit (1 bayt) kullanarak 28 = 256 karakter temsil eder.
- 0–127: standart ASCII karakterleri, her tabloda aynıdır. 128–255: özel karakterler, semboller ve ulusal harfler.
- Tek bir “genişletilmiş ASCII” yoktur: üst yarı kod sayfasına (code page) göre değişir. Türkçe için ISO-8859-9 (Latin-5) ve Windows-1254 kullanılır.
| Bayt | D0 | DD | DE | F0 | FD | FE | FC | E7 |
|---|---|---|---|---|---|---|---|---|
| ISO-8859-1 (Batı Avrupa) | Ð | Ý | Þ | ð | ý | þ | ü | ç |
| ISO-8859-9 (Türkçe) | Ğ | İ | Ş | ğ | ı | ş | ü | ç |
FE) bir tabloda ş, ötekinde þ'dir. Dosyayı yanlış kod sayfasıyla açmak “þimdi” gibi bozuk metinler üretir. Çözüm: tüm dilleri kapsayan Unicode / UTF-8.Dosyalar ve Kodlama
Bir Dosyaya Sayı (127) Yazma
- Bir sayının dosyada nasıl saklanacağı veri tipine, kullanım amacına ve dosya biçimine bağlıdır.
- Metin olarak: sayı önce karakterlere çevrilir; her rakam bir ASCII baytı tutar:
'1'karakterinin kodu 49'dur, 1 değil. - İkili olarak: sayının ikilik değeri (0111 1111) tipin boyutu kadar bayta doğrudan yazılır. Sayısal veri için daha verimlidir.
Dosyalar ve Kodlama
Metin mi, İkili mi? Karşılaştırma
| 127 nasıl yazıldı? | Boyut |
|---|---|
| ASCII / UTF-8 metin dosyası | 3 bayt |
| UTF-16 metin dosyası (BOM'suz) | 6 bayt |
İkili, byte | 1 bayt |
İkili, short | 2 bayt |
İkili, int | 4 bayt |
- Metin: insanlar okuyabilir, her düzenleyiciyle açılır, platformlar arası kolay taşınır. Kayıt dosyaları, ayarlar, CSV tabloları.
- İkili: sayısal veriyi daha küçük ve hızlı saklar; ama yazan programın biçimini bilmek gerekir. Resim, ses, veri tabanı dosyaları.
inther zaman 4 bayttır: 7 de, 2 000 000 000 de. Metinde ise boyut basamak sayısına bağlıdır (7 → 1 bayt, 2 000 000 000 → 10 bayt).
Java araçları: DataOutputStream ilkel tipleri ikili yazar (writeByte, writeShort, writeInt…), DataInputStream aynı sırayla geri okur; OutputStreamWriter karakterleri verilen kodlamayla bayta çevirir.
Dosyalar ve Kodlama
Kodla Doğrulama: 127
public class Sayi127 { static void metinYaz(String ad, Charset kod) throws IOException { Writer w = new OutputStreamWriter(new FileOutputStream(ad), kod); w.write(String.valueOf(127)); // "127": 3 karakter w.close(); } static void ikiliYaz(String ad, int boyut) throws IOException { FileOutputStream fos = new FileOutputStream(ad); DataOutputStream d = new DataOutputStream(fos); if (boyut == 1) d.writeByte(127); // 01111111 else if (boyut == 2) d.writeShort(127); // 00000000 01111111 else d.writeInt(127); // 4 byte d.close(); } public static void main(String[] args) throws IOException { metinYaz("metin.txt", StandardCharsets.US_ASCII); metinYaz("metin16.txt", StandardCharsets.UTF_16BE); ikiliYaz("b.dat", 1); ikiliYaz("s.dat", 2); ikiliYaz("i.dat", 4); String[] adlar = {"metin.txt", "metin16.txt", "b.dat", "s.dat", "i.dat"}; for (String ad : adlar) System.out.println(ad + ": " + new File(ad).length()); } }
metin.txt: 3 metin16.txt: 6 b.dat: 1 s.dat: 2 i.dat: 4
Dosya Sistemi
java.io.File Sınıfı
Filenesnesi diskteki bir yolu (path) temsil eder: bir dosya ya da klasör. Dosyanın içeriğini okumaz, yazmaz; bunu akışlar yapar.- Dosya sistemine erişip şu soruları cevaplar:
- Yol var mı yok mu? Bir dosya mı, klasör mü?
- Okunabilir, yazılabilir, çalıştırılabilir mi? Boyutu ve son değiştirilme zamanı ne?
- Yeni dosya veya klasör oluşturabilir, var olanı silebilir, bir klasörün içeriğini listeleyebilir.
new File("ornek.txt")diskte hiçbir şey oluşturmaz; yalnızca yolu tutar.
| Metot | Döndürdüğü |
|---|---|
exists() | yol var mı (boolean) |
isFile() / isDirectory() | dosya mı / klasör mü |
canRead(), canWrite(), canExecute() | izinler |
createNewFile() | oluşturuldu mu (varsa false) |
mkdir() / mkdirs() | klasör (ara klasörlerle) |
delete() | silindi mi (dolu klasör silinmez) |
list() / listFiles() | String[] / File[] |
length() | boyut (bayt, long) |
lastModified() | 1970'ten beri milisaniye |
getName(), getAbsolutePath() | ad, tam yol |
Dosya Sistemi
File ile Dosya ve Klasör İşlemleri
public class DosyaBilgi { public static void main(String[] args) throws IOException { File klasor = new File("ornek"); File dosya = new File("ornek/dosya.txt"); System.out.println("var mı: " + dosya.exists()); System.out.println("mkdir: " + klasor.mkdir()); System.out.println("oluştu: " + dosya.createNewFile()); System.out.println("dosya mı: " + dosya.isFile()); System.out.println("klasör mü: " + dosya.isDirectory()); System.out.println("okunur: " + dosya.canRead()); System.out.println("yazılır: " + dosya.canWrite()); System.out.println("boyut: " + dosya.length()); String[] icerik = klasor.list(); System.out.println("klasörde: " + icerik.length + " öğe"); long zaman = dosya.lastModified(); System.out.println("zaman > 0: " + (zaman > 0)); System.out.println("silindi: " + dosya.delete()); System.out.println("var mı: " + dosya.exists()); klasor.delete(); } }
var mı: false mkdir: true oluştu: true dosya mı: true klasör mü: false okunur: true yazılır: true boyut: 0 klasörde: 1 öğe zaman > 0: true silindi: true var mı: false
- Yol ayırıcı olarak
/her sistemde çalışır;File.separatorda kullanılabilir. - Göreli yol, programın çalıştığı klasöre göredir.
Metin Okuma ve Yazma
Scanner ile Dosya Okuma
public class ScannerDosya { public static void main(String[] args) { Scanner scanner = null; try { scanner = new Scanner(new File("ornekDosya.txt")); // Dosyanın içeriğini okuma ve ekrana yazdırma while (scanner.hasNextLine()) { String satir = scanner.nextLine(); System.out.println(satir); } } catch (FileNotFoundException e) { System.err.println("Dosya bulunamadı: " + e.getMessage()); } finally { if (scanner != null) scanner.close(); } } }
Java Giriş Çıkış Akışlar
- Dosya yoksa kontrol edilen bir istisna fırlatılır:
catchzorunlu. hasNextLine(): satır var mı?nextLine(): satırı al.- Dosya açılamazsa
scannernullkalır:finally'deki kontrol şart.
Scanner dosya içeriğini okumak ve işlemek için kullanılır; klavye ve String gibi diğer girdileri de okur. Gereken importlar: java.io.File, java.io.FileNotFoundException, java.util.Scanner. Scanner AutoCloseable'dır: try-with-resources ile finally ve null denetimi gerekmez.
Metin Okuma ve Yazma · Adım adım kod izleme
try-with-resources: Kapanış Sırası
class Kaynak implements AutoCloseable { String ad; Kaynak(String ad) { this.ad = ad; System.out.println(ad + " açıldı"); } public void close() { System.out.println(ad + " kapandı"); } } public class KapanisSirasi { public static void main(String[] args) { try (Kaynak a = new Kaynak("A"); Kaynak b = new Kaynak("B")) { System.out.println("blok çalışıyor"); throw new IllegalStateException("hata!"); } catch (IllegalStateException e) { System.out.println("yakalandı: " + e.getMessage()); } finally { System.out.println("finally"); } } }
Parantezdeki ilk kaynak oluşturulur; yapıcı mesaj yazar. a artık açık bir kaynaktır.
İkinci kaynak b açılır. Kaynaklar soldan sağa sırayla oluşturulur.
Blok gövdesi çalışır; iki kaynak da açıktır.
İstisna fırlatılır. catch'e geçmeden önce kaynaklar otomatik kapatılacak.
Kapatma ters sırayla başlar: önce en son açılan b'nin close() metodu çağrılır.
Ardından a.close() çağrılır. İstisna hâlâ yolda; henüz yakalanmadı.
Kaynaklar kapandıktan sonra catch istisnayı yakalar. Bu noktada a ve b kapsam dışıdır.
finally en son çalışır. Sıra: aç A, aç B, gövde, kapat B, kapat A, catch, finally.
Metin Okuma ve Yazma
Java I/O Kütüphanesi
java.iopaketi giriş/çıkış işlemleri için güçlü ve esnek bir araç seti sunar; dosya işlemlerinden ağ programlamaya kadar kullanılır.
Dosya, ağ, bellek gibi kaynaklardan veri almak ve göndermek.
Hem bayt tabanlı (ikili) hem karakter tabanlı (metin) işlemleri destekler.
Dosyadaki verilere hem sırayla hem istenen konuma atlayarak erişilebilir.
| Öğe tipi | Örnekler | Görevi |
|---|---|---|
| Sınıflar | File | dosya ve klasör (yol) işlemleri |
InputStream, OutputStream | temel bayt giriş/çıkışı | |
Reader, Writer | metin (karakter) giriş/çıkışı | |
| Arayüzler | Closeable, AutoCloseable | kaynağı serbest bırakma: close() |
Flushable | tamponu boşaltma: flush() | |
| İstisnalar | IOException | giriş/çıkış hatalarının üst sınıfı |
FileNotFoundException, EOFException | dosya yok / beklenmedik dosya sonu |
Metin Okuma ve Yazma
Bayt ve Karakter Odaklı Giriş Çıkış
Bayt akışları
InputStreamveOutputStreamsınıfları- Veri bayt (8 bit) dizileri olarak işlenir
- Resim, ses, video,
.classgibi ikili verilerle çalışır read()0–255 arası bir bayt döndürür
Karakter akışları
ReaderveWritersınıfları- Veri char (16 bit Unicode) olarak işlenir
- Metin tabanlı verilerle daha verimli çalışır
- Kodlamayı (UTF-8…) çözer: farklı dil ve alfabeleri destekler
| Bayt akışı | Karakter akışı | |
|---|---|---|
| Okuma birimi | byte | char |
| Dosya sınıfları | FileInputStream, FileOutputStream | FileReader, FileWriter |
| Tamponlu | BufferedInputStream, BufferedOutputStream | BufferedReader, BufferedWriter |
| Kullanım | her tür dosya, kopyalama | yalnızca metin dosyaları |
Köprü sınıflar: InputStreamReader bir bayt akışını karakter akışına, OutputStreamWriter karakterleri bayt akışına çevirir (kodlama burada uygulanır).
Metin Okuma ve Yazma
Bayt Akışı Sınıfları
İtalik kutular soyut (abstract) sınıflardır; içi boş üçgenli oklar kalıtımı gösterir. System.out bir PrintStream'dir. Filter… alt sınıfları başka bir akışı sarmalayıp yeni yetenek ekler (tampon, ilkel tip okuma).
Metin Okuma ve Yazma
Karakter Akışı Sınıfları
FileReader aslında bir InputStreamReader'dır: FileInputStream'den gelen baytları seçilen kodlamayla karakterlere çevirir. FileWriter da aynı şekilde OutputStreamWriter'dan türer.
Metin Okuma ve Yazma
Sarmalayıcı (Decorator) Akışlar
BufferedReader okuyucu = new BufferedReader(new FileReader("ornekDosya.txt")); PrintWriter yazici = new PrintWriter(new BufferedWriter(new FileWriter("dosya2.txt")));
- Her akış sınıfı tek bir işi iyi yapar; ihtiyaç duyulan yetenekler akışları iç içe sarmalayarak birleştirilir (Decorator tasarım deseni).
- Benzetme: hortumun ucuna önce filtre, sonra püskürtme başlığı takmak. Su (veri) hepsinden sırayla geçer.
- En dıştaki akışı kapatmak (
close()) içtekilerin hepsini de kapatır.
Metin Okuma ve Yazma
BufferedReader ile Satır Satır Okuma: Adım Adım
File yalnızca yolu tutar; dosya henüz açılmadı.
FileReader dosyayı açar, BufferedReader onu sarmalar. Okuma konumu dosyanın başında.
readLine() satırı okur, ⏎'i atar. Sonuç null değil → döngüye gir.
Satır ekrana yazılır.
Sıradaki satır okunur: satir = "Giriş Çıkış".
Satır ekrana yazılır.
Sıradaki satır okunur: satir = "Akışlar".
Satır ekrana yazılır.
Dosya sonu: readLine() null döndürür → döngü biter.
try biter: okuyucu otomatik kapatılır; catch çalışmaz.
import java.io.*; public class SatirOku { public static void main(String[] args) { File dosya = new File("ornekDosya.txt"); try (BufferedReader okuyucu = new BufferedReader(new FileReader(dosya))) { String satir; while ((satir = okuyucu.readLine()) != null) { System.out.println(satir); } } catch (IOException e) { System.err.println("Okuma hatası: " + e.getMessage()); e.printStackTrace(); } } }
Metin Okuma ve Yazma
java.io.PrintWriter
public class PrintWriterOrnek { public static void main(String[] args) { PrintWriter yazici = null; try { yazici = new PrintWriter("yeniDosya.txt"); yazici.println("Merhaba, dünya!"); yazici.println("Bu bir örnek dosyadır."); yazici.printf(Locale.ROOT, "Pi yaklaşık %.2f%n", Math.PI); yazici.println(42); } catch (IOException e) { System.err.println("Dosya hatası: " + e.getMessage()); e.printStackTrace(); } finally { if (yazici != null) yazici.close(); } } }
- Metin dosyalarına kolayca yazar:
print,println,printf. - Diğer tipleri metne çevirerek yazar.
- Dosya yoksa oluşturur, varsa içini siler.
closeunutulmamalı: veri tamponda kalabilir.
Merhaba, dünya! Bu bir örnek dosyadır. Pi yaklaşık 3.14 42
Metin Okuma ve Yazma
java.io.FileWriter
- Dosyalara karakter tabanlı veri yazmak için kullanılır; karakter akışına (
Writer) veri yazma işlevi sağlar. - Yalnızca
write(String),write(char[]),write(int c)vardır: metin biçimlendirme yetenekleri sınırlıdır, satır sonu (\n) ayrıca yazılır. - Daha düşük düzeyli ve esnek bir yaklaşımdır; çoğunlukla
BufferedWriterveyaPrintWriterile sarmalanır. new FileWriter(ad, true): dosyanın sonuna ekler (append);falseveya parametresiz hâli dosyayı sıfırlar.
FileWriter | BufferedWriter | PrintWriter | |
|---|---|---|---|
| Yazma metotları | write | write, newLine() | print, println, printf |
| Sayı yazmak | önce String'e çevir | önce String'e çevir | doğrudan: println(42) |
| Tampon | küçük iç tampon | 8192 karakterlik tampon | sardığı akışa bağlı |
| Hata bildirimi | IOException | IOException | checkError() |
Metin Okuma ve Yazma
FileWriter Örneği: Yazma ve Ekleme
public class FileWriterOrnek { public static void main(String[] args) { try (FileWriter yazici = new FileWriter("yeniDosya.txt")) { yazici.write("Merhaba, dünya!\n"); yazici.write("Bu bir FileWriter örneğidir.\n"); System.out.println("Dosya oluşturuldu ve veri yazıldı."); } catch (IOException e) { System.err.println("Dosya hatası: " + e.getMessage()); e.printStackTrace(); } // true: dosyanın sonuna ekle (append) try (FileWriter ekle = new FileWriter("yeniDosya.txt", true)) { ekle.write("Sona eklenen satır.\n"); } catch (IOException e) { System.err.println("Dosya hatası: " + e.getMessage()); } } }
Dosya oluşturuldu ve veri yazıldı.
Merhaba, dünya! Bu bir FileWriter örneğidir. Sona eklenen satır.
Metin Okuma ve Yazma
Karakter Kodlamasını Belirtmek
public class KodlamaOku { public static void main(String[] args) throws IOException { File dosya = new File("turkce.txt"); try (BufferedWriter yazici = new BufferedWriter( new FileWriter(dosya, StandardCharsets.UTF_8))) { // Java 11+ yazici.write("Işık, şimşek, çiğ, öğrenci, Ünye"); } try (BufferedReader dogru = new BufferedReader( new FileReader(dosya, StandardCharsets.UTF_8))) { System.out.println(dogru.readLine()); } try (BufferedReader yanlis = new BufferedReader( new FileReader(dosya, StandardCharsets.ISO_8859_1))) { System.out.println(yanlis.readLine()); } } }
Işık, şimşek, çiğ, öğrenci, Ünye IÅık, ÅimÅek, çiÄ, öÄrenci, Ãnye
- Kodlama verilmezse varsayılan kullanılır: Java 18+ UTF-8, eskiden işletim sisteminin ayarı (Windows-1254). Taşınabilir kodda kodlama açıkça verilir; Java 10 ve öncesinde
InputStreamReaderköprüsüyle. - Karşılığı olmayan karakter
?(3F) olur:şASCII'de3F, UTF-8'deC5 9F.
Tamponlama
Tamponlama (Buffering)
- Temel metotlar:
read()bir bayt veya bayt dizisi okur,write()bir bayt veya bayt dizisi yazar. - Her bayt için ayrı disk erişimi uygulamayı ciddi şekilde yavaşlatır: disk, bellekten binlerce kat yavaştır.
- Çözüm: veriyi bellekte bir tamponda (buffer) biriktirip diskten okuma / diske yazma işlemlerini toplu yapmak. Fiziksel disk erişimi sayısı azalır.
Tamponsuz yazma: her write() çağrısı doğrudan diske gider.
Tamponlu yazma: write() çağrıları baytları önce bellekteki tampona koyar.
Tampon dolunca, flush() veya close() çağrılınca tamponun tamamı tek seferde diske yazılır.
Tamponlama
Tamponlu Akış Sınıfları
| Sınıf | Sardığı akış | Ne yapar? |
|---|---|---|
BufferedInputStream | InputStream | okumayı hızlandırır: read() çağrıldığında diskten tek seferde 8192 baytı bellekteki önbelleğe alır |
BufferedReader | Reader | aynısı, karakterler için; ayrıca readLine() |
BufferedOutputStream | OutputStream | yazmayı hızlandırır: write() verisini önbellekte biriktirir |
BufferedWriter | Writer | aynısı, karakterler için; ayrıca newLine() |
public class FlushOrnek { public static void main(String[] args) throws IOException { File log = new File("log.txt"); BufferedWriter bw = new BufferedWriter(new FileWriter(log)); bw.write("Kayıt 1"); System.out.println("önce: " + log.length()); bw.flush(); System.out.println("sonra: " + log.length()); bw.close(); } }
önce: 0 sonra: 8
flush() tamponu hemen diske boşaltır; close() önce flush() yapar. Kapatılmayan tamponlu yazıcıda son veriler kaybolur.
Tamponlama · Adım adım kod izleme
Tampon ve flush: Adım Adım
File f = new File("log.txt"); PrintWriter pw = new PrintWriter(new FileWriter(f)); System.out.println("0: " + f.length()); pw.print("kayit1;"); System.out.println("1: " + f.length()); pw.print("kayit2;"); System.out.println("2: " + f.length()); pw.flush(); System.out.println("3: " + f.length()); pw.print("kayit3;"); pw.close(); System.out.println("4: " + f.length()); pw.print("kayit4;"); // kapalı: sessizce yok sayılır System.out.println("hata? " + pw.checkError());
FileWriter dosyayı oluşturur (boş). Yazılanlar önce bellekteki tampona gider.
Henüz hiçbir şey yazılmadı: 0 bayt.
print 7 karakteri tampona koyar; diske dokunmaz.
Dosya hâlâ 0 bayt: veri bellekte bekliyor.
İkinci kayıt da tampona eklenir; dosya yine 0 bayt.
flush() tamponu diske boşaltır: 14 bayt yazılır.
Artık uzunluk 14.
Üçüncü kayıt tampona girer.
close() önce flush() yapar, sonra dosyayı kapatır.
Dosya 21 bayt. close unutulsaydı son kayıt kaybolabilirdi.
PrintWriter istisna fırlatmaz; kapalı akışa yazma sessizce başarısız olur. Hata yalnızca checkError() ile görülür.
Tamponlama
BufferedInputStream ve BufferedReader
try { FileInputStream fis = new FileInputStream("dosya.txt"); BufferedInputStream bis = new BufferedInputStream(fis); int veri; while ((veri = bis.read()) != -1) { System.out.print((char) veri); } bis.close(); // içteki fis'i de kapatır } catch (IOException e) { System.err.println("Dosya hatası: " + e.getMessage()); }
Java I/O Tampon
try { FileReader fr = new FileReader("dosya.txt"); BufferedReader br = new BufferedReader(fr); String satir; while ((satir = br.readLine()) != null) { System.out.println(satir); } br.close(); // içteki fr'yi de kapatır } catch (IOException e) { System.err.println("Dosya hatası: " + e.getMessage()); }
Java I/O Tampon
Tamponlama
Tamponlama Ne Kadar Hızlandırır?
public class TamponOlcum { static long oku(InputStream in) throws IOException { long bas = System.nanoTime(); while (in.read() != -1) { } // her seferinde 1 byte in.close(); return (System.nanoTime() - bas) / 1_000_000; } public static void main(String[] args) throws IOException { File f = new File("buyuk.dat"); try (FileOutputStream fos = new FileOutputStream(f)) { fos.write(new byte[2 * 1024 * 1024]); // 2 MB } long t1 = oku(new FileInputStream(f)); long t2 = oku(new BufferedInputStream(new FileInputStream(f))); System.out.println("Tamponsuz: " + t1 + " ms"); System.out.println("Tamponlu : " + t2 + " ms"); f.delete(); } }
Tamponsuz: 3151 ms Tamponlu : 94 ms
- Aynı 2 MB dosya, iki kez bayt bayt okunuyor.
- Tamponsuz: 2 097 152
read()= o kadar sistem çağrısı. - Tamponlu: sistem çağrısı 8 KB'ta bir, 256 kez. Fark onlarca kat.
- Süreler makineye göre değişir; oran benzer kalır.
Diğer Bayt Akışları
java.io.FileInputStream
InputStream'dan türer; dosyadan doğrudan bayt okur. Düşük düzeylidir: resim, ses gibi metin dışı veriler için.read(): tek bayt (0–255), dosya sonunda −1.read(byte[] b): en fazlab.lengthbayt okur ve okuduğu sayıyı döndürür.- Metin için zordur (ü gibi çok baytlı karakterler bölünebilir);
FileReadergibi karakter tabanlı sınıflar daha uygundur.
public class ParcaOku { public static void main(String[] args) throws IOException { try (FileInputStream fis = new FileInputStream("dosya.txt")) { byte[] dizi = new byte[4]; int adet; while ((adet = fis.read(dizi)) != -1) { System.out.println(adet + ": " + new String(dizi, 0, adet)); } } } }
4: Merh 4: aba 4: Java
dosya.txt: “Merhaba Java”, 12 bayt, 4'erli parçalar. new String(dizi, 0, adet) yalnızca okunan kısmı çevirir.
Diğer Bayt Akışları
java.io.ByteArrayInputStream
InputStream'dan türer; bellekteki bir bayt dizisinden okur. Fiziksel kaynağa erişmez, veri bellekte olduğu için hızlıdır.- Yalnızca okunur; belleğe yazmak için eşi
ByteArrayOutputStreamvar. Büyük veride bellek tüketimi sorun olabilir.
public class ByteDiziOku { public static void main(String[] args) throws IOException { byte[] dizi = {74, 97, 118, 97}; // "Java" ByteArrayInputStream bais = new ByteArrayInputStream(dizi); int b; while ((b = bais.read()) != -1) { System.out.print(b + "=" + (char) b + " "); } System.out.println(); // Belleğe yazma: ByteArrayOutputStream ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(dizi); baos.write('!'); byte[] sonuc = baos.toByteArray(); System.out.println(sonuc.length + " byte: " + baos); } }
74=J 97=a 118=v 97=a 5 byte: Java!
Diğer Bayt Akışları
StringBufferInputStream: Kullanımdan Kaldırıldı
java.io.StringBufferInputStreamJava 1.1'den beri kullanımdan kaldırılmıştır (deprecated); kullanımı tavsiye edilmez.- Karakterleri bayta doğru çevirmez (yalnızca alt 8 bit). Yerine
ByteArrayInputStream+getBytes(UTF_8)veyaStringReader.
public class EskiAkis { @SuppressWarnings("deprecation") public static void main(String[] args) throws IOException { InputStream eski = new StringBufferInputStream("ş€"); int b; while ((b = eski.read()) != -1) { System.out.print(b + " "); } System.out.println(); byte[] dogru = "ş€".getBytes("UTF-8"); InputStream yeni = new ByteArrayInputStream(dogru); while ((b = yeni.read()) != -1) { System.out.print(b + " "); } System.out.println(); } }
95 172 197 159 226 130 172
ş (351) → 95 = _, € → 172. Doğrusu UTF-8: 197 159 226 130 172.
Diğer Bayt Akışları
PipedInputStream ve PipedOutputStream
InputStream/OutputStreamsınıflarından türetilmiştir; iki iş parçacığı (thread) arasında güvenli veri iletişimi sağlar.- Bir iş parçacığı
PipedOutputStreamile veri yazar, diğeriPipedInputStreamile bu veriyi okur. İki uçnew PipedOutputStream(pis)ile bağlanır. - Okuma ve yazma senkronizedir: boru boşsa okuyucu bekler, doluysa yazıcı bekler.
- Yalnızca tek yönlü veri iletimini destekler; çift yön için iki boru gerekir.
- İki ucu aynı iş parçacığında kullanmak kilitlenmeye (deadlock) yol açabilir.
Diğer Bayt Akışları
Boru Örneği
PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis);
// Okuyucu iş parçacığı Thread okuyucu = new Thread(() -> { try { int b; while ((b = pis.read()) != -1) System.out.print((char) b); System.out.println(); pis.close(); } catch (IOException e) { e.printStackTrace(); } });
// Yazıcı iş parçacığı Thread yazici = new Thread(() -> { try { pos.write("Merhaba, boru!".getBytes()); pos.close(); } catch (IOException e) { e.printStackTrace(); } }); okuyucu.start(); yazici.start(); yazici.join(); okuyucu.join();
Merhaba, boru!
start()iş parçacığını başlatır;join()bitmesini bekler.- Yazıcı
pos.close()deyince okuyucununread()'i −1 döner, döngü biter.
Diğer Bayt Akışları
java.io.SequenceInputStream
- Birden fazla
InputStream'i birleştirerek ardışık tek bir giriş akışı oluşturur: birinci akış bitince (−1) ikinciye geçer. - Farklı kaynaklardan gelen veriyi tek akışta birleştirir. Bir akışta hata olursa
IOExceptionfırlatılır, diğerine geçilmez.
try { FileInputStream is1 = new FileInputStream("dosya1.txt"); FileInputStream is2 = new FileInputStream("dosya2.txt"); SequenceInputStream sis = new SequenceInputStream(is1, is2); int okunanByte; while ((okunanByte = sis.read()) != -1) System.out.print((char) okunanByte); sis.close(); // is1 ve is2'yi de kapatır } catch (IOException e) { System.err.println("Okuma hatası: " + e.getMessage()); }
Birinci dosya. Ikinci dosya.
sis.close() içteki akışları da kapatır.
Dosya Kopyalama
Bayt Bayt Dosya Kopyalama
- Kaynak dosyadan okunan her baytı hedef dosyaya yazar: her tür dosyayı (metin, resim,
.exe) bozmadan kopyalar. BufferedInputStreamveBufferedOutputStreamgiriş ve çıkışı hızlandırır: önbellek kullanarak okuma ve yazmayı toplu yapar.bis.read(): bir bayt okur, dosyanın sonunda −1 döner.bos.write(veri): okunan baytı çıkış dosyasına yazar.- Okunan değer
intbir değişkende tutulmalıdır: −1 ile 255 bayt değerini ayırt etmek için.
Kopyalama döngüsü tek satırdır: while ((veri = bis.read()) != -1) bos.write(veri);
Dosya Kopyalama
Bayt Bayt Kopyalama: Adım Adım
İki File nesnesi yalnızca yolları tutar.
FileOutputStream hedef dosyayı oluşturur (varsa içini siler): 0 bayt.
İki akış tamponlu akışlarla sarmalanır; tamponlar (8192 bayt) boş.
İlk read(): tampon boş olduğu için diskten tek seferde 4 baytın tamamı tampona alınır; ilk bayt 74 ('J') döner.
write baytı çıkış tamponuna koyar; dosya2.txt hâlâ 0 bayt.
Bu kez diske gidilmez: bayt tampondan gelir (97 = 'a').
Çıkış tamponunda artık 2 bayt var.
Bu kez diske gidilmez: bayt tampondan gelir (118 = 'v').
Çıkış tamponunda artık 3 bayt var.
Bu kez diske gidilmez: bayt tampondan gelir (97 = 'a').
Çıkış tamponunda artık 4 bayt var.
Tampon boşaldı; diskten ikinci okuma dosya sonunu bildirir: read() −1 döndürür, döngü biter.
close() önce flush() yapar: 4 bayt tek seferde diske yazılır, sonra fos kapanır.
Giriş akışları da kapatılır.
Diskte 2 okuma (ikincisi yalnızca dosya sonunu bildirir) ve 1 yazma oldu; tamponsuz olsaydı 5 okuma ve 4 yazma olurdu.
import java.io.*; public class BaytKopya { public static void main(String[] args) throws IOException { File dosya = new File("dosya.txt"); File dosya2 = new File("dosya2.txt"); FileInputStream fis = new FileInputStream(dosya); FileOutputStream fos = new FileOutputStream(dosya2); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); int veri; // Bir byte oku. Dosyanın sonunda -1 dönecektir. while ((veri = bis.read()) != -1) bos.write(veri); // Okunan byte'ı çıkışa yaz bos.close(); bis.close(); System.out.println(dosya2.length() + " byte kopyalandı"); } }
Dosya Kopyalama
Blok Blok (Parça Parça) Kopyalama
public class ParcaKopya { public static void main(String[] args) throws IOException { // Veri, 16K'lık parçalar hâlinde okunacak byte[] parca = new byte[1024 * 16]; File dosya = new File("dosya.txt"); File dosya2 = new File("dosya2.txt"); FileInputStream fis = new FileInputStream(dosya); FileOutputStream fos = new FileOutputStream(dosya2); BufferedInputStream bis = new BufferedInputStream(fis); BufferedOutputStream bos = new BufferedOutputStream(fos); int boyut; // 16K'ya kadar oku. Dosyanın sonunda -1 dönecektir. while ((boyut = bis.read(parca)) > -1) bos.write(parca, 0, boyut); // Okunan parçayı çıkışa yaz bos.close(); bis.close(); System.out.println(dosya2.length() + " byte kopyalandı"); } }
40000 byte kopyalandı
- Toplu okuma performansı artırır.
read(parca): okunan bayt sayısını döndürür.write(parca, 0, boyut): yalnızca ilkboyutbaytı yazar.
new byte[1024 * 16]: veri 16 KB'lık parçalar hâlinde işlenir; dosya ne kadar büyük olursa olsun bellek kullanımı sabit kalır.
Dosya Kopyalama
Blok Blok Kopyalama: Adım Adım
16 baytlık bir dizi (gerçek programlarda 8–16 KB).
İki kaynak birlikte açılır; try bitince ikisi de kapanacak.
read(parca) diziyi doldurur, 16 döner.
write(parca, 0, 16): yalnızca okunan 16 bayt yazılır.
Okunan miktar yazdırılır.
Sonraki 16 bayt aynı dizinin üzerine yazılır.
write(parca, 0, 16): yalnızca okunan 16 bayt yazılır.
Okunan miktar yazdırılır.
Yalnızca 7 bayt kaldı: dizinin ilk 7 öğesi yenilenir, kalan 9'u önceki bloktan kalma!
write(parca, 0, 7): yalnızca okunan 7 bayt yazılır. write(parca) deseydik eski 9 bayt da yazılır, kopya 48 bayt olurdu.
Okunan miktar yazdırılır.
Dosya sonu: −1 döner, > -1 yanlış, döngü biter.
Kaynaklar kapandı; kopya kaynakla aynı boyutta: 16 + 16 + 7 = 39 bayt.
public class ParcaIzle { public static void main(String[] args) throws IOException { byte[] parca = new byte[16]; try (InputStream in = new FileInputStream("dosya.txt"); OutputStream out = new FileOutputStream("dosya2.txt")) { int boyut; while ((boyut = in.read(parca)) > -1) { out.write(parca, 0, boyut); System.out.println("boyut = " + boyut); } } long n = new File("dosya2.txt").length(); System.out.println("Bitti: " + n + " byte"); } }
Dosya Kopyalama
Satır Satır Dosya Kopyalama
public class SatirKopya { public static void main(String[] args) throws IOException { File dosya = new File("dosya.txt"); File dosya2 = new File("dosya2.txt"); FileReader fr = new FileReader(dosya); BufferedReader br = new BufferedReader(fr); FileWriter fw = new FileWriter(dosya2); BufferedWriter bw = new BufferedWriter(fw); PrintWriter pw = new PrintWriter(bw); String satir; // dosya sonuna kadar bir satır oku while ((satir = br.readLine()) != null) pw.println(satir); // satırı yaz pw.close(); br.close(); System.out.println("Kopyalandı: " + dosya2.getName()); } }
Kopyalandı: dosya2.txt
- Karakter akışlarıyla çalışır: yalnızca metin dosyaları için.
readLine()satır sonunu atar;printlnsistemin satır sonunu ekler (Windows:\r\n, Linux:\n). Kopya bayt bayt aynı olmayabilir.pw.close()zincirin tamamını (bw,fw) kapatır.
Dosya Kopyalama
Web Sayfası İndirme
public class WebIndir { public static void main(String[] args) throws IOException { URL url = URI.create("https://sercankulcu.github.io/").toURL(); BufferedInputStream bis = new BufferedInputStream(url.openStream()); FileOutputStream fos = new FileOutputStream(new File("kopya.html")); BufferedOutputStream bos = new BufferedOutputStream(fos); for (int c = bis.read(); c != -1; c = bis.read()) { bos.write(c); } bis.close(); bos.close(); System.out.println("kopya.html: " + new File("kopya.html").length() + " byte"); } }
kopya.html: 14283 byte
- Kaynak bir dosya değil, ağ:
url.openStream()birInputStreamdöndürür; kopyalama döngüsü aynıdır. new URL(String)Java 20'den beri kullanımdan kaldırıldı;URI.create(…).toURL()önerilir.fordöngüsü: oku, −1 değilse yaz, tekrar oku.
Dosya Kopyalama
Kısa Yollar: transferTo ve Files.copy
public class KopyaKisa { public static void main(String[] args) throws IOException { // Java 9+: transferTo try (InputStream in = new FileInputStream("dosya.txt"); OutputStream out = new FileOutputStream("dosya2.txt")) { long adet = in.transferTo(out); System.out.println(adet + " byte aktarıldı"); } // Java 7+: Files.copy Files.copy(Path.of("dosya.txt"), Path.of("dosya3.txt"), StandardCopyOption.REPLACE_EXISTING); System.out.println(Files.size(Path.of("dosya3.txt")) + " byte kopyalandı"); } }
4 byte aktarıldı 4 byte kopyalandı
Kütüphane metotları içeride blok kopyalama yapar. Files.copy hedef varsa REPLACE_EXISTING seçeneği olmadan FileAlreadyExistsException fırlatır.
Dosya Kopyalama
Kopyalama Yöntemleri
| Yöntem | Birim | Uygun olduğu durum |
|---|---|---|
Bayt bayt (read()/write(int)) | 1 bayt | öğrenmek için; tamponsuz çok yavaş |
Blok blok (read(byte[])) | 8–16 KB | her tür dosya, hızlı |
Satır satır (readLine/println) | 1 satır | yalnızca metin; satırları işlerken |
in.transferTo(out) (Java 9+) | blok | iki akış arasında tek satırda kopya |
Files.copy(kaynak, hedef) (Java 7+) | blok | dosyadan dosyaya en kısa yol |
IOException ele alınır.Rastgele Erişim
Dosya Erişimi: Sıralı ve Rastgele
Sıralı erişim (sequential)
- Her okuma/yazma bir sonraki konumdan devam eder; geri dönülemez.
- Dosya içeriğinin yapısı bilinmediğinde veya kopya oluşturulurken kullanılır.
- Akışların (
FileInputStream,BufferedReader…) hepsi sıralıdır.
Rastgele erişim (random access)
- Dosya içinde istenen konuma hareket edilip oradan okunur/yazılır.
- Kayıtların boyutu ve konumu biliniyorsa kullanılabilir: k. kayıt = k × kayıt boyutu.
- Belirli bir kaydı okumak veya yerinde değiştirmek için kullanışlıdır.
Rastgele Erişim
java.io.RandomAccessFile
| Üye | Görevi |
|---|---|
RandomAccessFile(String ad, String mod) | mod "r": okuma, "rw": okuma ve yazma |
seek(long konum) | dosya işaretçisini belirtilen konuma taşır |
getFilePointer() | işaretçinin dosya başına uzaklığı (bayt) |
length() | dosyanın uzunluğu (bayt) |
read() / write(int b) | bir bayt okur (int olarak döndürür) / yazar |
readInt(), writeInt(int), readDouble()… | ilkel tipleri ikili okur/yazar (int: 4 bayt) |
close() | sistem kaynaklarını serbest bırakır |
Akışlardan farklı olarak tek bir nesne hem okur hem yazar; InputStream / OutputStream hiyerarşisinde değildir.
Rastgele Erişim
Sıralı ve Rastgele Erişim: Kod
public class RasgeleErisim { public static void main(String[] args) throws IOException { // Sıralı Erişim FileInputStream sirali = new FileInputStream("dosya"); int bayt = sirali.read(); sirali.close(); System.out.println("İlk byte: " + bayt); // Rasgele Erişim RandomAccessFile rast = new RandomAccessFile("dosya", "rw"); // Dosyanın başından 100 byte ilerideki konuma git rast.seek(100); // 100. konumdan itibaren 4 byte'lık bir int oku int veri = rast.readInt(); System.out.println("100. konumdaki int: " + veri); rast.close(); } }
İlk byte: 1 100. konumdaki int: 256
seek(100) işaretçiyi 100 konumuna, yani 101. bayta taşır (konumlar 0'dan başlar). Oradaki 4 bayt 00 00 01 00 olduğundan readInt() = 256 döner. dosya burada 124 baytlık bir veri dosyasıdır.
Rastgele Erişim
Kayıtlara Rastgele Erişim: Adım Adım
"rw": dosya yoksa oluşturulur. İşaretçi 0'da.
Yazılacak beş not.
Her writeInt 4 bayt yazar ve işaretçiyi 4 ilerletir.
Döngü bitti: 5 × 4 = 20 bayt, işaretçi dosya sonunda (20).
length() = 20.
3. kayıt (indis 2) 8. baytta başlar: doğrudan oraya atlanır, öncekiler okunmaz.
readInt() 8–11. baytları okur: 90. İşaretçi 12'ye ilerler.
getFilePointer() = 12.
4. kayıt da 12'de başlıyor; işaretçi zaten orada.
45 yerine 50 yerinde yazılır; dosyanın geri kalanı değişmez. Sıralı akışla bu yapılamaz.
Başa dönülür.
İşaretçi uzunluğa ulaşana kadar okunur: 70 + 85 + 90 + 50 + 60 = 355.
Sonuç yazdırılır; ardından dosya kapatılır.
import java.io.*; public class Kayitlar { public static void main(String[] args) throws IOException { RandomAccessFile f = new RandomAccessFile("n.dat", "rw"); int[] notlar = {70, 85, 90, 45, 60}; for (int n : notlar) f.writeInt(n); // her kayıt 4 byte System.out.println("Uzunluk: " + f.length()); f.seek(2 * 4); // 3. kayda git System.out.println("3. not: " + f.readInt()); System.out.println("Konum: " + f.getFilePointer()); f.seek(3 * 4); // 4. kayıt f.writeInt(50); // 45 yerine 50 f.seek(0); int toplam = 0; while (f.getFilePointer() < f.length()) toplam += f.readInt(); System.out.println("Toplam: " + toplam); f.close(); } }
Serileştirme
Serileştirme (Serialization)
- Serileştirme: bir nesnenin durumunu (alan değerlerini) bayt dizisine çevirmek; bu sayede nesne dosyaya yazılabilir, ağ üzerinden başka bir ortama taşınabilir. Tersi serileştirmeyi geri alma (deserialization).
- Bir sınıfın nesneleri serileştirilebilmesi için sınıf
java.io.Serializablearayüzünü uygulamalıdır (metodu olmayan bir işaret arayüzü). - Sınıfın sürüm kimliği
serialVersionUIDile belirtilmesi önerilir; yazılmazsa serileştirme mekanizması sınıfın yapısından hesaplar ve sınıf değişince eski dosyalar okunamaz. staticalanlar (sınıfa aittir) vetransient(geçici) olarak işaretlenen alanlar serileştirilmez; şifre gibi alanları dışarıda bırakmak için kullanılır.
Serileştirme
Serileştirme Akışı
Bellekte bir Ogrenci nesnesi var.
ObjectOutputStream.writeObject nesneyi baytlara çevirir; dosya AC ED sihirli sayısıyla başlar.
ObjectInputStream.readObject baytlardan yeni bir nesne kurar: aynı değerler, farklı nesne.
Serileştirme
Serileştirilebilir Sınıf
import java.io.Serializable; class Ogrenci implements Serializable { private static final long serialVersionUID = 1L; private String ad; private int yas; public Ogrenci(String ad, int yas) { this.ad = ad; this.yas = yas; } public String toString() { return "Ogrenci [ad=" + ad + ", yas=" + yas + "]"; } }
implements Serializable: metodu olmayan bir işaret arayüzü.serialVersionUID: sınıfın sürüm numarası. Yazan ve okuyan sürüm farklıysaInvalidClassException.- Alanlar da serileştirilebilir olmalı; değilse
NotSerializableException. readObjectObjectdöndürür:(Ogrenci)dönüşümü gerekir.
Serileştirme
Nesneyi Yazma ve Geri Okuma
// Serileştirme işlemi try (ObjectOutputStream cikti = new ObjectOutputStream( new FileOutputStream("ogrenci.ser"))) { Ogrenci ogrenci = new Ogrenci("Ahmet", 20); cikti.writeObject(ogrenci); System.out.println("Serileştirme başarılı."); } catch (IOException e) { e.printStackTrace(); } System.out.println("ogrenci.ser: " + new File("ogrenci.ser").length() + " byte"); // Seriyi okuma işlemi try (ObjectInputStream girdi = new ObjectInputStream( new FileInputStream("ogrenci.ser"))) { Ogrenci ogrenci = (Ogrenci) girdi.readObject(); System.out.println("Ogrenci: " + ogrenci); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
Serileştirme başarılı. ogrenci.ser: 72 byte Ogrenci: Ogrenci [ad=Ahmet, yas=20]
Serileştirme
transient ve static Alanlar
class Kullanici implements Serializable { private static final long serialVersionUID = 1L; static int sayac; private String ad; private transient String sifre; // yazılmaz Kullanici(String ad, String sifre) { this.ad = ad; this.sifre = sifre; } public String toString() { return "Kullanici [ad=" + ad + ", sifre=" + sifre + "]"; } }
transient: bu alan serileştirmede atlanır; geri okunduğunda varsayılan değeri alır (null, 0,false).- Şifre, geçici önbellek, açık dosya/bağlantı gibi saklanmaması gereken veya saklanamayan alanlar için.
staticalanlar nesneye değil sınıfa aittir: dosyaya hiç yazılmaz.
Serileştirme
transient ve static: Deneme
Kullanici k = new Kullanici("ayse", "gizli123"); Kullanici.sayac = 5; ObjectOutputStream c = new ObjectOutputStream( new FileOutputStream("k.ser")); c.writeObject(k); c.close(); Kullanici.sayac = 99; // static: sınıfa ait ObjectInputStream g = new ObjectInputStream( new FileInputStream("k.ser")); Kullanici okunan = (Kullanici) g.readObject(); g.close(); System.out.println(okunan); System.out.println("sayac = " + Kullanici.sayac); System.out.println("aynı nesne mi? " + (okunan == k));
Kullanici [ad=ayse, sifre=null] sayac = 99 aynı nesne mi? false
sifre→null: yazılmadı.sayac→ 99: bellekteki son değer.==yanlış: okunan, yeni bir nesne.
Serileştirme · Adım adım kod izleme
Serileştirme: Yazma ve Geri Okuma Adım Adım
Kullanici k = new Kullanici("ayse", "gizli123"); Kullanici.sayac = 5; ObjectOutputStream c = new ObjectOutputStream( new FileOutputStream("k.ser")); c.writeObject(k); c.close(); Kullanici.sayac = 99; // static: sınıfa ait ObjectInputStream g = new ObjectInputStream( new FileInputStream("k.ser")); Kullanici okunan = (Kullanici) g.readObject(); g.close(); System.out.println(okunan); System.out.println("sayac = " + Kullanici.sayac); System.out.println("aynı nesne mi? " + (okunan == k));
Heap'te yeni bir Kullanici nesnesi: ad ve sifre dolu. static sayac sınıf alanında, 0.
sayac nesneye değil sınıfa aittir; tek kopyası vardır.
Akış açılır ve dosyaya hemen 4 baytlık akış başlığını yazar.
writeObject sınıf tanımını ve alanları yazar: dosya 63 bayt. transient sifre ve static sayac yazılmaz.
Akış kapatılır; dosya 63 bayt olarak kalır.
Sınıftaki sayac 99 olur. Dosyada sayac olmadığı için okuma bunu değiştiremez.
Okuma akışı açılır; önce akış başlığını denetler.
Heap'te yeni bir nesne kurulur; yapıcı çağrılmaz. ad dosyadan gelir, sifre varsayılan değer null olur.
toString() okunan nesnenin alanlarını yazar.
sayac bellekteki son değerdir: 99.
İki ayrı nesne: içerikleri benzese de referanslar farklıdır.
NIO
NIO (New I/O)
- Java NIO (
java.nio, Java 1.4+), gelişmiş G/Ç işlemleri için güçlü bir API sunar: tampon (buffer), kanal (channel), seçici (selector) ve dosya sistemi entegrasyonu içerir. - Klasik
java.ioakışlarına göre performans ve esneklik sağlar.
Veriyi geçici olarak depolayan bellek alanları.
Giriş/çıkış işlemlerini yöneten, çift yönlü bağlantı nesneleri.
Birden çok kanalı tek iş parçacığında yönetir; girdi bekleyen kanalları izler.
Dosya ve dizin yollarını temsil eder (Java 7+, NIO.2).
NIO.2 (java.nio.file, Java 7+) dosya işlemleri için Path ve Files sınıflarını ekledi.
NIO
Akış mı, Kanal mı?
Klasik G/Ç (java.io) | NIO (java.nio) | |
|---|---|---|
| Temel kavram | akış (stream) | kanal (channel) + tampon (buffer) |
| Yön | tek yön: girdi ya da çıktı | kanal çift yönlü olabilir |
| Birim | bayt / karakter | tampon dolusu blok |
| Bekleme | her zaman bloklayan | bloklamayan (non-blocking) mod da var |
| Çok bağlantı | bağlantı başına bir iş parçacığı | tek iş parçacığı + seçici |
| Ne zaman? | basit dosya/konsol işleri | çok sayıda bağlantılı sunucular, büyük dosyalar |
NIO
NIO Tamponları
- Tampon: verileri geçici olarak saklayan, sabit boyutlu bir bellek alanıdır (bir dizi + konum bilgileri).
- Her ilkel tip için bir sınıf:
ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer. - Oluşturma:
ByteBuffer.allocate(1024)veya var olan diziyi sarmak:ByteBuffer.wrap(dizi).
| Özellik | Anlamı |
|---|---|
| kapasite (capacity) | tutulabilecek en fazla öğe; hiç değişmez |
| konum (position) | bir sonraki okuma/yazmanın yapılacağı indis |
| sınır (limit) | okunabilecek/yazılabilecek ilk olmayan indis |
| işaret (mark) | mark() ile saklanan konum; reset() oraya döner |
Her zaman: 0 ≤ mark ≤ position ≤ limit ≤ capacity.
NIO
ByteBuffer Örneği
public class TamponOrnek { public static void main(String[] args) { // 1 KB boyutunda bir ByteBuffer oluştur ByteBuffer buffer = ByteBuffer.allocate(1024); // Veri yazma buffer.put("Merhaba, Java!".getBytes()); System.out.println("put sonrası : " + buffer); // Buffer'ı okuma moduna geçirme buffer.flip(); System.out.println("flip sonrası : " + buffer); // Veriyi okuma while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } System.out.println(); } }
put sonrası : java.nio.HeapByteBuffer[pos=14 lim=1024 cap=1024] flip sonrası : java.nio.HeapByteBuffer[pos=0 lim=14 cap=1024] Merhaba, Java!
putyazar, konum 14'e ilerler.flip(): sınır = 14, konum = 0: okuma modu.hasRemaining(): konum < sınır mı?
NIO
Tampon ve Türkçe Karakterler
public class TamponUmlaut { public static void main(String[] args) { ByteBuffer b = ByteBuffer.allocate(64); b.put("Dünya".getBytes(StandardCharsets.UTF_8)); b.flip(); while (b.hasRemaining()) System.out.print((char) b.get()); // yanlış System.out.println(); b.rewind(); System.out.println(StandardCharsets.UTF_8.decode(b)); // doğru } }
Dᅢᄐnya Dünya
(char) buffer.get() yalnızca ASCII metinde doğrudur. “Dünya” UTF-8'de 6 bayttır (ü = C3 BC); baytları tek tek char'a çevirmek ü'yü bozar. Metni çözmek için Charset.decode kullanılmalıdır.
NIO
put, flip, get, compact, rewind, clear: Adım Adım
Boş tampon: konum 0, sınır = kapasite = 8.
put konuma yazar ve konumu 1 ilerletir.
Konum 2.
Konum 3.
4 bayt yazıldı; konum 4.
flip(): sınır = eski konum (4), konum = 0. Yalnızca yazılan 4 bayt okunabilir.
get() konumdaki baytı döndürür, konum 1 olur.
c2 = 'A'; okunmamış 2 bayt kaldı (V, A).
compact(): okunmamış V, A başa kopyalanır; konum 2, sınır 8. 2–3'teki eski baytlar silinmez, üzerine yazılacak.
'!' konum 2'ye yazılır; eski 'V'nin üzerine.
Okumaya geç: sınır 3 (V, A, !).
Bir bayt okunur ('V'), konum 1.
rewind(): konum 0, sınır değişmez: aynı veri baştan yeniden okunabilir.
clear(): konum 0, sınır 8. Veri silinmez; sadece “boş” sayılır, üzerine yazılır.
toString() tamponun konum, sınır ve kapasitesini gösterir.
import java.nio.ByteBuffer; public class TamponIzle { public static void main(String[] args) { ByteBuffer b = ByteBuffer.allocate(8); b.put((byte) 'J'); b.put((byte) 'A'); b.put((byte) 'V'); b.put((byte) 'A'); b.flip(); char c1 = (char) b.get(); char c2 = (char) b.get(); b.compact(); b.put((byte) '!'); b.flip(); b.get(); b.rewind(); b.clear(); System.out.println(c1 + "" + c2 + " " + b); } }
NIO
Tampon İşlemleri
| Metot | Ne yapar? | position | limit |
|---|---|---|---|
put(x) | konuma veri yazar | +1 | — |
get() | konumdaki veriyi okur | +1 | — |
flip() | yazmadan okumaya geçer | 0 | eski position |
rewind() | aynı veriyi baştan yeniden okumak için | 0 | değişmez |
clear() | yeniden yazmaya hazırlar; veriyi silmez | 0 | capacity |
compact() | okunmamış veriyi başa taşır, yazmaya devam eder | kalan sayısı | capacity |
mark() / reset() | konumu işaretler / işarete döner | — / mark | — |
Avantajlar
- Veri üzerinde esnek gezinme ve değiştirme
- Verimli bellek yönetimi: tek alan tekrar tekrar kullanılır
Dezavantajlar
- Kullanımı karmaşıktır (
flipunutmak sık hata) - Boyutu sonradan değiştirilemez
NIO
ByteBuffer Deneme Alanı
Yeşil hücreler position ile limit arasıdır: yazma modunda boş yer, okuma modunda okunacak veri. Örnek sıra: üç kez put, flip, iki kez get, compact; ya da flip etmeden get.
NIO
NIO Kanalları (Channel)
- Kanal, giriş ve çıkış verilerini yönetir: bir dosya, soket veya belirli bir protokol üzerinden veri alışverişi sağlar.
- Veri her zaman bir tampon üzerinden okunur (
read(tampon)) veya yazılır (write(tampon)).
| Kanal türü | Kullanımı |
|---|---|
FileChannel | dosyada okuma ve yazma |
SocketChannel | TCP ağ soketi üzerinden veri iletimi |
ServerSocketChannel | gelen TCP bağlantılarını kabul etme |
DatagramChannel | UDP soketi üzerinden veri iletimi |
NIO
Kanal Oluşturma ve Kapatma
public class KanalAcKapa { public static void main(String[] args) throws IOException { // FileChannel oluşturma FileChannel fileChannel = FileChannel.open( Paths.get("dosya.txt"), StandardOpenOption.READ); // SocketChannel oluşturma SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("example.com", 80)); System.out.println("Bağlandı: " + socketChannel.isConnected()); // Kanal kapatma fileChannel.close(); socketChannel.close(); } }
Bağlandı: true
FileChannel.open(yol, seçenekler…) dosya kanalı, SocketChannel.open() + connect ağ kanalı açar. Kanallar da close() ile (veya try-with-resources ile) kapatılmalıdır.
NIO
FileChannel ile Okuma
public class KanalOku { public static void main(String[] args) throws IOException { try (FileChannel channel = FileChannel.open( Paths.get("dosya.txt"), StandardOpenOption.READ)) { ByteBuffer buffer = ByteBuffer.allocate(1024); // Dosyadan veriyi okuma int bytesRead = channel.read(buffer); System.out.println(bytesRead + " byte okundu"); // Buffer'ı okuma moduna geçirme buffer.flip(); // Veriyi ekrana yazma while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } } } }
17 byte okundu NIO kanal ornegi
channel.read(buffer) tampona okur, okunan bayt sayısını (dosya sonunda −1) döndürür. Okumadan önce flip() unutulmamalı.
NIO
FileChannel ile Yazma
public class KanalYaz { public static void main(String[] args) throws IOException { try (FileChannel kanal = FileChannel.open(Paths.get("cikti.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { byte[] veri = "Kanal ile yazıldı\n".getBytes(StandardCharsets.UTF_8); ByteBuffer tampon = ByteBuffer.wrap(veri); int yazilan = kanal.write(tampon); System.out.println(yazilan + " byte yazıldı"); } } }
20 byte yazıldı
ByteBuffer.wrap(dizi) hazır bir diziyi tampon olarak kullanır (konum 0, sınır = dizi boyu); bu yüzden flip() gerekmez. CREATE: dosya yoksa oluştur.
NIO
SocketChannel Kullanımı
try (SocketChannel socketChannel = SocketChannel.open()) { socketChannel.connect(new InetSocketAddress("example.com", 80)); ByteBuffer buffer = ByteBuffer.allocate(1024); buffer.put(("GET / HTTP/1.1\r\nHost: example.com\r\n" + "Connection: close\r\n\r\n").getBytes(StandardCharsets.US_ASCII)); buffer.flip(); // Veriyi sokete yazma socketChannel.write(buffer); // Cevabı okuma buffer.clear(); socketChannel.read(buffer); buffer.flip(); String cevap = StandardCharsets.US_ASCII.decode(buffer).toString(); System.out.println(cevap.substring(0, cevap.indexOf("\r\n"))); } catch (IOException e) { e.printStackTrace(); }
HTTP/1.1 200 OK
main gövdesi. Ağ bağlantısı da bir kanaldır: aynı put / flip / write kalıbı. HTTP/1.1 isteğinde Host başlığı zorunludur.
NIO
NIO: Avantajlar ve Dezavantajlar
Avantajlar
- Performans: bloklar hâlinde, klasik G/Ç'den verimli aktarım
- Esneklik: tampon ve kanallarla esnek veri işleme; çift yönlü kanallar
- Dosya ve ağ için aynı yöntem
- Çoklu bağlantı: seçiciyle birden çok kanal tek iş parçacığında; yalnızca etkin kanallar işlenir
Dezavantajlar
- Karmaşıklık: klasik G/Ç'ye göre daha zor
- Tampon durumunu ve hata durumlarını (yarım okuma, kopan bağlantı) yönetmek gerekir
- Seçici için öğrenme eğrisi: çok kanalın durumunu doğru izlemek gerekir
BufferedReader veya Files yeterlidir. Kanallar, çok büyük dosyalar ve çok sayıda ağ bağlantısı için öne çıkar.NIO
Path ve Files (NIO.2)
public class DosyalarNio { public static void main(String[] args) throws IOException { Path yol = Path.of("veri", "notlar.txt"); // Java 11+ Files.createDirectories(yol.getParent()); Files.writeString(yol, "Ali 70\nAyşe 85\nCan 90\n"); System.out.println(yol.getFileName() + ": " + Files.exists(yol)); System.out.println("Boyut: " + Files.size(yol) + " byte"); List<String> satirlar = Files.readAllLines(yol); for (String satir : satirlar) { System.out.println(satir.toUpperCase(Locale.ROOT)); } Files.write(yol, List.of("Deniz 60"), StandardOpenOption.APPEND); System.out.println(Files.readAllLines(yol).size() + " satır"); } }
notlar.txt: true Boyut: 23 byte ALI 70 AYŞE 85 CAN 90 4 satır
| Metot | Görevi |
|---|---|
Path.of(…) / Paths.get(…) | yol oluşturur (File'ın modern karşılığı) |
Files.readAllLines, Files.readString | tüm dosyayı tek çağrıda okur (UTF-8) |
Files.write, Files.writeString | tek çağrıda yazar |
Files.exists, size, copy, move, delete | dosya sistemi işlemleri |
NIO
NIO Seçici (Selector)
- Birden çok kanalı tek bir iş parçacığında izleme mekanizmasıdır.
Selector.open()ile yeni bir seçici oluşturulur.- Kanal bloklamayan moda alınır ve seçiciye kaydedilir:
channel.register(selector, ops). - Kanalın hangi olayları beklediği
SelectionKeysabitleriyle belirlenir.select()en az bir kanal hazır olana kadar bekler.
| SelectionKey | Anlamı |
|---|---|
OP_READ | kanaldan okuma yapılabilir |
OP_WRITE | kanala yazma yapılabilir |
OP_CONNECT | bağlantı kurma tamamlandı |
OP_ACCEPT | bağlantı kabul edilebilir |
NIO
Seçici ile Sunucu
public class SeciciGoster { public static void main(String[] args) throws IOException { ServerSocketChannel kanal = ServerSocketChannel.open(); Selector secici = Selector.open(); kanal.bind(new InetSocketAddress(8080)); kanal.configureBlocking(false); kanal.register(secici, SelectionKey.OP_ACCEPT); while (true) { int hazirKanallar = secici.select(); if (hazirKanallar > 0) { Set<SelectionKey> secilenler = secici.selectedKeys(); for (SelectionKey secilen : secilenler) { if (secilen.isAcceptable()) { // Bağlantı kabul } else if (secilen.isReadable()) { // Veri okuma } } secilenler.clear(); // İşlenen anahtarları temizle } } } }
- Sunucu kanalı 8080 portuna bağlanır, bloklamayan moda alınır,
OP_ACCEPTiçin kaydedilir. select()hazır kanal sayısını,selectedKeys()hazır anahtarları verir.- İşlenen anahtarlar
clear()ile temizlenmezse sonraki turda yine gelir. - Gerçek sunucuda kabul edilen istemci
OP_READile kaydedilir ve veri okunur.
Özet
Özet
| Konu | Anahtar sınıf / metot | Hatırlanacak |
|---|---|---|
| Akışlar | System.in, System.out, System.err, Scanner | veri kaynaktan hedefe sırayla akar |
| Metin / ikili | ASCII, ISO-8859-9, UTF-8; DataOutputStream | 127: metin 3 bayt, int 4 bayt; aynı kodlamayla oku-yaz |
| Dosya sistemi | File, Path, Files | File yalnızca yoldur, içeriği okumaz |
| Metin okuma/yazma | Scanner, BufferedReader, PrintWriter, FileWriter | readLine() sonda null; FileWriter(ad, true) ekler |
| Bayt akışları | FileInputStream, ByteArray…, Piped…, Sequence… | read() sonda −1; okunan int'te tutulur |
| Tamponlama | Buffered…, flush() | disk erişimini toplu yapar; akış kapatılmalı |
| Kopyalama | read(byte[]), write(b, 0, n), Files.copy | yalnızca okunan n bayt yazılır |
| Rastgele erişim | RandomAccessFile, seek | k. kayıt = k × kayıt boyu |
| Serileştirme | Serializable, ObjectOutputStream, transient | static/transient yazılmaz |
| NIO | ByteBuffer, FileChannel, Selector | yazdıktan sonra flip(), tekrar yazmadan önce clear()/compact() |
Özet
Sık Yapılan Hatalar (1)
error: unreported exception FileNotFoundException; must be caught or declared to be thrownnew FileReader("a.txt") try-catch içinde olmalı ya da metot throws IOException demeli.
error: cannot find symbol symbol: class Scannerimport java.util.Scanner; (G/Ç sınıfları için import java.io.*;).
error: illegal escape character new File("C:\dersler\notlar.txt")\n, \d kaçış dizisi sayılır. "C:\\dersler\\notlar.txt" veya "C:/dersler/notlar.txt" yazılır.
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.Scanner.close()"Dosya açılamayınca scanner null kalır. if (scanner != null) ya da try-with-resources gerekir.
Özet
Sık Yapılan Hatalar (2)
Yaş: 19⏎ Ad: Ayşe⏎ → çıktı: [] 19nextInt() satır sonunu tamponda bırakır; ardından gelen nextLine() boş satırı okur. Araya bir klavye.nextLine(); eklenir.
bw.write("kayit"); // close yok not.txt boyutu: 0Veri tamponda kalır, dosya boş görünür. close() (veya flush()) çağrılmalı; en iyisi try-with-resources.
b.put((byte) 'J'); b.put((byte) 'A'); b.get() → 0 (konum 2'deki boş hücre)Yazdıktan sonra okumadan önce flip() şarttır; yoksa yazılan veri değil, sonrası okunur.
java.io.NotSerializableException: ArabawriteObject edilen sınıf (ve alanlarının tipleri) implements Serializable olmalı.
byte b; while ((b = (byte) in.read()) != -1)255 değerli byte (−1'e dönüşür) dosya sonu sanılır. Doğru tip int'tir.
out.write(parca); // son blokta eski veri de giderSon blokta dizi tam dolmaz; doğrusu write(parca, 0, boyut).
Özet
Örnek Problemler (1)
try (PrintWriter pw = new PrintWriter("s.txt")) { pw.print(12); pw.print(' '); pw.print(345); } System.out.println(new File("s.txt").length()); try (DataOutputStream d = new DataOutputStream(new FileOutputStream("s.dat"))) { d.writeInt(12); d.writeInt(345); } System.out.println(new File("s.dat").length());
- Bu kod ne yazdırır?
12ve345önce metin, sonra ikili olarak yazılıyor.
Cevabı göster
- 6 ve 8. Metin:
"12 345"= 6 karakter = 6 bayt. İkili: ikiint= 2 × 4 = 8 bayt.
Özet
Örnek Problemler (2)
try (FileWriter w = new FileWriter("a.txt")) { w.write("ab"); } try (FileWriter w = new FileWriter("a.txt")) { w.write("cd"); } try (FileWriter w = new FileWriter("a.txt", true)) { w.write("ef"); } try (BufferedReader r = new BufferedReader(new FileReader("a.txt"))) { System.out.println(r.readLine()); }
- Bu kod ne yazdırır?
a.txtbaşta yok.
Cevabı göster
- cdef. İkinci
FileWriterdosyayı sıfırlar (“ab” silinir), üçüncüsütrueile sona ekler.
Özet
Örnek Problemler (3)
ByteBuffer b = ByteBuffer.allocate(10); b.put((byte) 1).put((byte) 2).put((byte) 3); b.flip(); b.get(); System.out.println(b.position() + " " + b.limit() + " " + b.remaining()); b.compact(); System.out.println(b.position() + " " + b.limit()); b.clear(); System.out.println(b.position() + " " + b.limit() + " " + b.get(0));
- Bu kod üç satırda ne yazdırır?
Cevabı göster
- 1 3 2 / 2 10 / 0 10 2.
flip: konum 0, sınır 3; birget→ konum 1, kalan 2.compact: 2 ve 3 başa taşınır, konum 2, sınır 10.clear: konum 0, sınır 10; veri silinmez,get(0)= 2.
Özet
Örnek Problemler (4)
try (RandomAccessFile f = new RandomAccessFile("r.dat", "rw")) { for (int i = 1; i <= 4; i++) f.writeInt(i * 10); f.seek(4); int a = f.readInt(); f.seek(f.length() - 4); int b = f.readInt(); System.out.println(a + " " + b + " " + f.getFilePointer()); }
- Bu kod ne yazdırır?
Cevabı göster
- 20 40 16. Kayıtlar 10, 20, 30, 40 (her biri 4 bayt).
seek(4)→ 20.length() - 4= 12 → 40. Okumadan sonra işaretçi 16, yani dosya sonu.
Özet
Alıştırmalar (1)
- Sayaç:
metin.txtdosyasının satır, kelime ve karakter sayısını (satır sonları hariç) bulan bir program yazın. Dosya: “Java ile dosya / okuma ve yazma / (boş satır) / çok kolay”.
Çözüm
int satirSayisi = 0, kelimeSayisi = 0, karakterSayisi = 0; try (BufferedReader br = new BufferedReader(new FileReader("metin.txt"))) { String satir; while ((satir = br.readLine()) != null) { satirSayisi++; karakterSayisi += satir.length(); String temiz = satir.trim(); if (!temiz.isEmpty()) kelimeSayisi += temiz.split("\\s+").length; } } catch (IOException e) { System.err.println("Hata: " + e.getMessage()); } System.out.println(satirSayisi + " satır, " + kelimeSayisi + " kelime, " + karakterSayisi + " karakter");
4 satır, 8 kelime, 37 karakter
Özet
Alıştırmalar (2)
- Kareler: klavyeden
nokuyun; 1..nsayılarını ve karelerinikareler.txt'ye yazın, sonra dosyayı okuyup kareler toplamını bulun.
Çözüm
Scanner klavye = new Scanner(System.in); try (PrintWriter pw = new PrintWriter(new FileWriter("kareler.txt"))) { int n = klavye.nextInt(); for (int i = 1; i <= n; i++) { pw.println(i + " " + i * i); } } int toplam = 0; try (Scanner dosya = new Scanner(new File("kareler.txt"))) { while (dosya.hasNextInt()) { dosya.nextInt(); // i toplam += dosya.nextInt(); // i * i } } System.out.println("Kareler toplamı: " + toplam);
Kareler toplamı: 55
Özet
Alıştırmalar (3)
- Dizi saklama:
int[] dizi = {3, 1, 4, 1, 5}dizisinidizi.ser'e serileştirin, geri okuyup öğe sayısını ve toplamını yazdırın (diziler serileştirilebilir).
Çözüm
int[] dizi = {3, 1, 4, 1, 5}; try (ObjectOutputStream c = new ObjectOutputStream(new FileOutputStream("dizi.ser"))) { c.writeObject(dizi); } try (ObjectInputStream g = new ObjectInputStream(new FileInputStream("dizi.ser"))) { int[] okunan = (int[]) g.readObject(); int toplam = 0; for (int x : okunan) toplam += x; System.out.println(okunan.length + " eleman, toplam " + toplam); }
5 eleman, toplam 14
Özet
Alıştırmalar (4)
- Not dosyası: 5 notu
RandomAccessFileileintolarak yazın. Verilen sıra numarasındaki notu dosyanın tamamını okumadan bulun. Hangi konumaseekedilmeli? - Düşünün: 10 000 satırlık bir kayıt dosyasının yalnızca son kaydını okumak için sıralı akış mı, rastgele erişim mi uygundur? Satır boyları farklıysa ne değişir?
Cevaplar / ipuçları
f.seek((sira - 1) * 4); int not = f.readInt();3. notun konumu 8.- Sabit boylu kayıtlarda rastgele erişim: doğrudan
seek((n - 1) * boy). Satır boyları farklıysa konum hesaplanamaz: baştan sıralı okunur ya da sondan geriye\naranır.
Özet
Kaynaklar
- Oracle, The Java Tutorials: “Basic I/O” (I/O Streams, File I/O featuring NIO.2), “Scanning and Formatting”.
- Oracle, Java SE 21 API Documentation:
java.io,java.nio,java.nio.channels,java.nio.filepaketleri. - Oracle, Java Object Serialization Specification.
- J. Gosling ve diğ., The Java Language Specification, Java SE 21 Edition (3.10.6 kaçış dizileri, 14.20.3 try-with-resources).
- P. Deitel ve H. Deitel, Java: How to Program, Early Objects, 11. baskı, Pearson, 2017 (Bölüm 15: Files, Input/Output Streams, NIO and XML Serialization).
- C. S. Horstmann, Core Java, Volume II: Advanced Features, 12. baskı, 2022 (Bölüm 2: Input and Output).
- K. Sierra ve B. Bates, Head First Java, 3. baskı, O'Reilly, 2022 (Bölüm 16: Saving Objects (and Text)).
- A. B. Downey ve C. Mayfield, Think Java, 2. baskı, O'Reilly, 2019.