Bölüm 7: Giriş Çıkış
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ç byte 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 byte 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 sizi 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 | Türü |
|---|---|---|
| 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. Dikkat: satır sonu (⏎) 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 byte dizisidir. Farkı, bu byte'ların nasıl yorumlandığı yaratır.
- Metin dosyaları (text): byte'lar bir karakter kodlamasına göre harflere çevrilir; insanlar okuyabilir.
- İkili dosyalar (binary): byte'lar 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 byte'ın onaltılık değeri, sağda ASCII karşılığı. 4D = 77 = M. 15 harf 16 byte tutar: ü UTF-8'de iki byte'tı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 byte'lar 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 byte yazar;write(127)tek byte7F.read(): byte'ı 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 (byte'larla) 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 byte. Web'in ve Java 18+ sürümünün varsayılanı.
Dosyalar ve Kodlama
İkili Dosyalar
- Byte'ları 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 byte):
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 byte'larıyla başlar: JVM dosyanın türünü bu “sihirli sayıdan” tanır.
Dosyalar ve Kodlama
ASCII Tablosu
- ASCII (American Standard Code for Information Interchange): bilgisayarlar arasında metin değişimini standartlaştırmak için 1963'te tanımlanan karakter kodlamasıdır.
- 7 bit kullanır: 27 = 128 karakter (0–127). Her karakter bir sayı ile temsil edilir.
- Temel karakterler: harf, rakam, noktalama, temel semboller (32–126). Kontrol karakterleri: iletimde özel işlevli, ekrana basılmayan karakterler (0–31 ve 127): satır sonu, sekme, zil…
| Karakter | A | a | 0 | boşluk | \n (LF) | \t sekme |
|---|---|---|---|---|---|---|
| Onluk | 65 | 97 | 48 | 32 | 10 | 9 |
| Onaltılık | 41 | 61 | 30 | 20 | 0A | 09 |
| İkilik | 01000001 | 01100001 | 00110000 | 00100000 | 00001010 | 00001001 |
Büyük ve küçük harf arasındaki fark her zaman 32'dir (A = 65, a = 97): tek bir bitin farkı.
Dosyalar ve Kodlama
Java'da char ve Kod Değeri
public class AsciiOrnek { public static void main(String[] args) { char harf = 'A'; int kod = harf; // char -> int: 65 System.out.println(harf + " = " + kod); System.out.println((int) 'a'); // 97 System.out.println((char) 97); // a System.out.println((char) (harf + 2)); // C System.out.println('7' - '0'); // 7 (rakamın değeri) System.out.println(Integer.toBinaryString('A')); } }
A = 65 97 a C 7 1000001
char16 bitlik bir sayıdır; ilk 128 değeri ASCII ile aynı.int→chariçin(char)dönüşümü gerekir.'7' - '0'= 55 − 48 = 7.
Dosyalar ve Kodlama
Genişletilmiş ASCII ve Türkçe Karakterler
- Genişletilmiş ASCII (extended ASCII): 8 bit (1 byte) 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.
| Byte | 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
Unicode ve UTF-8
- Unicode, dünyadaki her karaktere tek bir numara (kod noktası, code point) verir:
A= 65,ş= 351 (U+015F),€= 8364. - UTF-8 bu numarayı 1–4 byte ile yazar: ASCII karakterleri yine 1 byte (geriye uyumlu), Türkçe harfler 2 byte, € 3 byte. UTF-16 çoğu karakter için 2 byte kullanır; Java'nın
chartürü UTF-16 birimidir.
| Karakter | Kod noktası | ASCII | ISO-8859-9 | UTF-8 | UTF-16 |
|---|---|---|---|---|---|
A | 65 | 41 | 41 | 41 | 00 41 |
7 | 55 | 37 | 37 | 37 | 00 37 |
ş | 351 | 3F | FE | C5 9F | 01 5F |
ğ | 287 | 3F | F0 | C4 9F | 01 1F |
ı | 305 | 3F | FD | C4 B1 | 01 31 |
€ | 8364 | 3F | 3F | E2 82 AC | 20 AC |
3F = ?: kodlamada karşılığı olmayan karakter soru işaretine dönüşür (veri kaybı). Bu tablo "ş".getBytes(StandardCharsets.UTF_8) gibi çağrılarla Java'da üretildi.
Dosyalar ve Kodlama
Deneyin: Karakter Kodlama
| Karakter | Kod noktası | ASCII | ISO-8859-9 | UTF-8 | UTF-16 |
|---|---|---|---|---|---|
| Toplam |
Kırmızı 3F: o kodlamada karşılığı yok, Java getBytes ile yazarken ? koyar. “Toplam” satırı, bu metni o kodlamayla kaydeden bir dosyanın kaç byte olacağını gösterir.
Dosyalar ve Kodlama
Bir Dosyaya Sayı (127) Yazma
- Bir sayının dosyada nasıl saklanacağı veri türüne, kullanım amacına ve dosya biçimine bağlıdır.
- Metin olarak: sayı önce karakterlere çevrilir; her rakam bir ASCII byte'ı tutar. Dikkat:
'1'karakterinin kodu 49'dur, 1 değil. - İkili olarak: sayının ikilik değeri (0111 1111) türün boyutu kadar byte'a 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 byte |
| UTF-16 metin dosyası (BOM'suz) | 6 byte |
İkili, byte | 1 byte |
İkili, short | 2 byte |
İkili, int | 4 byte |
- 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 byte'tır: 7 de, 2 000 000 000 de. Metinde ise boyut basamak sayısına bağlıdır (7 → 1 byte, 2 000 000 000 → 10 byte).
Java araçları: DataOutputStream ilkel türleri ikili yazar (writeByte, writeShort, writeInt…), DataInputStream aynı sırayla geri okur; OutputStreamWriter karakterleri verilen kodlamayla byte'a ç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 (byte, 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 denetlenen 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.
Metin Okuma ve Yazma
try-with-resources (Java 7+)
public class ScannerTwr { public static void main(String[] args) { try (Scanner scanner = new Scanner(new File("notlar.txt"))) { int toplam = 0, adet = 0; while (scanner.hasNextInt()) { toplam += scanner.nextInt(); adet++; } double ort = (double) toplam / adet; System.out.println(adet + " not, ortalama " + ort); } catch (FileNotFoundException e) { System.err.println("Dosya bulunamadı: " + e.getMessage()); } } }
5 not, ortalama 70.0
- Parantezde açılan kaynak blok bitince otomatik kapatılır; hata olsa bile.
finallyvenullkontrolü gerekmez.- Kaynak
AutoCloseableolmalı: akışlar,Scanner, kanallar. - Birden çok kaynak
;ile ayrılır, ters sırayla kapanır. nextInt()sayıları boşluk ve satır sonuna bakmadan okur.
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 byte tabanlı (ikili) hem karakter tabanlı (metin) işlemleri destekler.
Dosyadaki verilere hem sırayla hem istenen konuma atlayarak erişilebilir.
| Öğe türü | Örnekler | Görevi |
|---|---|---|
| Sınıflar | File | dosya ve klasör (yol) işlemleri |
InputStream, OutputStream | temel byte 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 byte (8 bit) dizileri olarak işlenir
- Resim, ses, video,
.classgibi ikili verilerle çalışır read()0–255 arası bir byte 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 tür okuma).
Metin Okuma ve Yazma
Karakter Akışı Sınıfları
FileReader aslında bir InputStreamReader'dır: FileInputStream'den gelen byte'ları 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("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 türleri 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 sonunu (\n) kendiniz yazarsınız. - Daha düşük seviyeli 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 | 8 KB 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 kod için kodlamayı açıkça yazın; Java 10 ve öncesinde
InputStreamReaderköprüsüyle.
Tamponlama
Tamponlama (Buffering)
- Temel metotlar:
read()bir byte veya byte dizisi okur,write()bir byte veya byte dizisi yazar. - Her byte 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ı byte'ları ö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 byte'ı 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
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 byte byte 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 byte okur. Düşük seviyelidir: resim, ses gibi metin dışı veriler için.read(): tek byte (0–255), dosya sonunda −1.read(byte[] b): en fazlab.lengthbyte okur ve okuduğu sayıyı döndürür.- Metin için zordur (ü gibi çok byte'lı 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 byte, 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 byte 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: Kullanmayın
java.io.StringBufferInputStreamJava 1.1'den beri kullanımdan kaldırılmıştır (deprecated); kullanımı tavsiye edilmez.- Karakterleri byte'a 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. İş parçacıkları Bölüm 9'da ayrıntılı işlenecek.
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 byte'ı 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 byte okur, dosyanın sonunda −1 döner.bos.write(veri): okunan byte'ı çıkış dosyasına yazar.- Okunan değer
intbir değişkende tutulmalıdır: −1 ile 255 byte 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 byte.
İki akış tamponlu akışlarla sarmalanır; tamponlar (8192 byte) boş.
İlk read(): tampon boş olduğu için diskten tek seferde 4 byte'ın tamamı tampona alınır; ilk byte 74 ('J') döner.
write byte'ı çıkış tamponuna koyar; dosya2.txt hâlâ 0 byte.
Bu kez diske gidilmez: byte tampondan gelir (97 = 'a').
Çıkış tamponunda artık 2 byte var.
Bu kez diske gidilmez: byte tampondan gelir (118 = 'v').
Çıkış tamponunda artık 3 byte var.
Bu kez diske gidilmez: byte tampondan gelir (97 = 'a').
Çıkış tamponunda artık 4 byte var.
Okunacak byte kalmadı: read() −1 döndürür, döngü biter.
close() önce flush() yapar: 4 byte tek seferde diske yazılır, sonra fos kapanır.
Giriş akışları da kapatılır.
Diskte 1 okuma 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 byte sayısını döndürür.write(parca, 0, boyut): yalnızca ilkboyutbyte'ı 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 byte'lı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 byte yazılır.
Okunan miktar yazdırılır.
Sonraki 16 byte aynı dizinin üzerine yazılır.
write(parca, 0, 16): yalnızca okunan 16 byte yazılır.
Okunan miktar yazdırılır.
Yalnızca 7 byte kaldı: dizinin ilk 7 elemanı yenilenir, kalan 9'u önceki bloktan kalma!
write(parca, 0, 7): yalnızca okunan 7 byte yazılır. write(parca) deseydik eski 9 byte da yazılır, kopya 48 byte 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 byte.
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 byte byte 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"); } }
- 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 byte | öğ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.Rasgele Erişim
Dosya Erişimi: Sıralı ve Rasgele
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.
Rasgele 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.
Rasgele 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ığı (byte) |
length() | dosyanın uzunluğu (byte) |
read() / write(int b) | bir byte okur (int olarak döndürür) / yazar |
readInt(), writeInt(int), readDouble()… | ilkel türleri ikili okur/yazar (int: 4 byte) |
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.
Rasgele Erişim
Sıralı ve Rasgele 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. byte'a taşır (konumlar 0'dan başlar). Oradaki 4 byte 00 00 01 00 olduğundan readInt() = 256 döner. dosya burada 124 byte'lık bir veri dosyasıdır.
Rasgele Erişim
Kayıtlara Rasgele Erişim: Adım Adım
"rw": dosya yoksa oluşturulur. İşaretçi 0'da.
Yazılacak beş not.
Her writeInt 4 byte yazar ve işaretçiyi 4 ilerletir.
Döngü bitti: 5 × 4 = 20 byte, işaretçi dosya sonunda (20).
length() = 20.
3. kayıt (indeks 2) 8. byte'ta başlar: doğrudan oraya atlanır, öncekiler okunmaz.
readInt() 8–11. byte'ları 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) byte 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ü gerçeklemelidir (metodu olmayan bir işaret arayüzü). - Sınıfın sürüm kimliği
serialVersionUIDile belirtilmesi önerilir; yazılmazsa derleyici sınıf yapısından üretir 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 byte'lara çevirir; dosya AC ED sihirli sayısıyla başlar.
ObjectInputStream.readObject byte'lardan 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.
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 | byte / 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 tür 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 eleman; hiç değişmez |
| konum (position) | bir sonraki okuma/yazmanın yapılacağı indeks |
| sınır (limit) | okunabilecek/yazılabilecek ilk olmayan indeks |
| 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 byte'tır (ü = C3 BC); byte'ları 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 byte yazıldı; konum 4.
flip(): sınır = eski konum (4), konum = 0. Yalnızca yazılan 4 byte okunabilir.
get() konumdaki byte'ı döndürür, konum 1 olur.
c2 = 'A'; okunmamış 2 byte kaldı (V, A).
compact(): okunmamış V, A başa kopyalanır; konum 2, sınır 8. 2–3'teki eski byte'lar silinmez, üzerine yazılacak.
'!' konum 2'ye yazılır; eski 'V'nin üzerine.
Okumaya geç: sınır 3 (V, A, !).
Bir byte 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
Deneyin: ByteBuffer
Yeşil hücreler position ile limit arasıdır: yazma modunda boş yer, okuma modunda okunacak veri. Deneyin: üç kez put, flip, iki kez get, compact. Ya da flip etmeden get deyin.
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 byte 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()); } 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 byte, int 4 byte; 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; kapatmayı unutma |
| Kopyalama | read(byte[]), write(b, 0, n), Files.copy | yalnızca okunan n byte yazılır |
| Rasgele 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ın.
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 kullanın.
Ö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(); ekleyin.
bw.write("kayit"); // close yok not.txt boyutu: 0Veri tamponda kalır, dosya boş görünür. close() (veya flush()) çağırın; en iyisi try-with-resources.
b.put('J'); b.put('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 türleri) 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. int kullanın.
out.write(parca); // son blokta eski veri de giderSon blokta dizi tam dolmaz; write(parca, 0, boyut) yazın.
Ö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 byte. İkili: ikiint= 2 × 4 = 8 byte.
Ö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 byte).
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 eleman 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ı, rasgele 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 rasgele 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.