---
title: 'Dosya ve Girdi/Çıktı'
source: 'https://academia.sh/tr/kurslar/ruby-temelleri/dosya-ve-girdi-cikti'
course: 'Ruby Temelleri'
language: tr
updated: '2026-10-21T05:03:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'File.read, File.readlines ve File.foreach ile dosyadan okur, File.write ile yazar'
    - 'Bloklu ve bloksuz File.open çağrısının dönüş değerini ve closed? durumunu ayırt eder'
    - 'Standart girdiyi bir borudan besleyip satır satır okur'
    - 'Blok istisna fırlatsa da dosyanın kapandığını ölçer ve kaynak temizlemeyi bloğun değil yöntemin üstlendiğini söyler'
---

# Dosya ve Girdi/Çıktı

File.open çağrısında sonucu bloğun, dosyanın kapanmasını ise yöntemin belirlediği ölçülür; blok istisna fırlatsa da dosya kapanır. Ders, kursun on iki gözleminin kapanış tablosunu da verir.

Önceki dersin sonunda `ensure` her durumda koşan bir dal olarak görüldü. Dosyalar bu yapının en sık kullanıldığı yerdir: açılan bir dosya kapatılmak zorundadır ve kapatmayı unutmak bir sızıntıdır. Ruby'de `File.open` çağrısına bir blok verilebilir; soru, kapatma işinin kime ait olduğudur. **Girdi/çıktı (input/output)**, programın dış dünyayla, yani dosyalarla ve standart akışlarla veri alışverişidir.

Bu dersin yanıtlayanı **blok**tur: `File.open` iletisi aynı dosyaya iki farklı blokla iki farklı sonuç verir. Dersin sonunda kursun on iki gözleminin tamamı tek tabloda toplanır.

## Dosya Okuma Gözlemi

Çekirdeğin on ikinci gözlemi `dosya okuma`'dır. Sınıflandırma yardımcısı `yanit.rb` kursun başından beri aynıdır ve burada yalnız diske yazılır.

```ruby
# yanit.rb — bir iletiyi kimin yanitladigini siniflandiran yardimcilar

# Siniflandirma sirayla sorar: once ifade bir ileti mi (defined?),
# sonra iki farkli blok iki farkli sonuc veriyor mu, sonra yontemin sahibi kim.
def yanitlayan(tanim, sahip: nil, sonuc: nil, bloklu: nil)
  return ["sozdizimi", "defined? #{tanim}"] unless tanim == "method"

  if bloklu
    birinci, ikinci = bloklu.call
    return ["blok", "#{birinci.inspect} / #{ikinci.inspect}"] unless birinci == ikinci
  end

  tur = sahip.instance_of?(Class) ? "sinif" : "modul"
  [tur, "#{sahip}, sonuc #{sonuc.inspect}"]
end
```

```ruby
# dosya_okuma.rb — ayni File.open iki blokla iki sonuc verir
require_relative "yanit"

File.write("not.txt", "ilk satir\nikinci satir\n")

tanim = defined?(File.open("not.txt"))
tur, kanit = yanitlayan(tanim, bloklu: -> {
  [File.open("not.txt") { |f| f.gets.chomp }, File.open("not.txt") { |f| f.readlines.size }]
})
puts tanim
puts "#{tur}  #{kanit}"
puts File.method(:open).owner.instance_of?(Class)
```

```
method
blok  "ilk satir" / 2
true
```

`File.write` iki satırlık `not.txt` dosyasını yazdı. `defined?` bloksuz çağrıyı `"method"` olarak bildirdi, yani ortada bir ileti var. İlk blok ilk satırı, ikinci blok satır sayısını döndürdü: aynı ileti, `"ilk satir"` ve `2`. Yanıtlayan **blok**tur. `File.open`'ın sahibi bir sınıftır (`instance_of?(Class)` `true`); sahibin tekil sınıf olarak görünmesi ikinci kursun konusudur ve burada yalnız sonucu okunur. **KB56.** Ölçüm tek bir dosya ve iki blokla yapıldı.

## Satır Okuma ve Yazma Akışları

Bloksuz kısa yollar, dosyayı açıp kapatma işini kendileri yapar. `File.write` yazılan bayt sayısını döndürür; `File.readlines` satırları bir dizi yapar ve `chomp: true` satır sonunu atar; `File.foreach` satırları tek tek verir. Olmayan bir dosya `Errno::ENOENT` fırlatır. Hata iletisi yol taşıdığı için yalnız sınıf basılır.

```ruby
# akislar.rb — yazma, okuma ve eksik dosya
File.write("not.txt", "ilk satir\nikinci satir\n")

puts File.write("b.txt", "abc")
puts File.readlines("not.txt", chomp: true).inspect
puts File.foreach("not.txt").count
begin
  File.read("yok.txt")
rescue Errno::ENOENT => e
  puts e.class
end
```

```
3
["ilk satir", "ikinci satir"]
2
Errno::ENOENT
```

`abc` üç bayttır ve `File.write` `3` döndürdü. `readlines` iki dizgiden oluşan bir dizi verdi. `foreach` bloksuz çağrıldığında bir yineleyici döndürür; `count` onu tüketip `2` buldu. Eksik dosya `Errno::ENOENT` fırlattı ve dal onu yakaladı. **KB57.** `File.write` yalnız dizgi içerikle ölçüldü.

Açık bir dosyayla çalışırken satır okuma yöntemleri örneğin üzerinde çağrılır. Bunların sahibi de ölçülebilir.

```ruby
# sahipler.rb — dosya ve standart cikti yontemlerinin sahibi
File.write("not.txt", "ilk satir\nikinci satir\n")

File.open("not.txt") do |f|
  puts f.class
  puts f.method(:gets).owner
  puts f.method(:each_line).owner
end
puts $stdout.method(:puts).owner
```

```
File
IO
IO
IO
```

Dosya nesnesi bir `File`'dır, ama `gets` ve `each_line` onun kendi sınıfında değil `IO` sınıfında tanımlıdır. `$stdout.puts` de aynı `IO` sınıfındadır. Dosya ile standart çıktı aynı sınıf ailesinin üyesidir ve bu üçünde de yanıtlayan sınıftır. **KB58.** Sahipler Ruby 4.0.7'de ölçüldü; hangi yöntemin hangi sınıfta tanımlı olduğu sürümden sürüme taşınabilir.

## Açık Kalan ve Kapanan Dosya

`File.open` bloksuz çağrılırsa dosya nesnesini döndürür ve dosya açık kalır; kapatmak çağıranın işidir. Bloklu çağrıda ise dosya nesnesi bloğa verilir, blok bitince dosya kapanır ve çağrının değeri bloğun son ifadesidir.

```ruby
# kapanma.rb — bloksuz ve bloklu File.open
File.write("not.txt", "ilk satir\nikinci satir\n")

f = File.open("not.txt")
puts f.class
puts f.closed?
f.close
puts f.closed?

tutulan = nil
deger = File.open("not.txt") do |dosya|
  tutulan = dosya
  puts dosya.closed?
  42
end
puts deger
puts tutulan.closed?
```

```
File
false
true
false
42
true
```

Bloksuz çağrı `File` döndürdü, `closed?` `false` çıktı ve ancak elle `close` çağrılınca `true` oldu. Bloklu çağrıda dosya blok içinde açıktı. Blok `42` ile bitti: dönüş değeri `42` oldu, blok dışına taşınan dosya nesnesi ise artık kapalıydı. Sonuç bloktan, kapanma yöntemden gelir. **KB59.** Ölçüm yerel dosya ve tek bir blok için yapıldı.

## Açma Kipleri

`File.open` ikinci argüman olarak bir kip alır. `"w"` dosyayı açarken sıfırlar, `"a"` mevcut içeriğin sonuna ekler. Fark satır sayısıyla ölçülür. Bloklu `File.open` çağrısının değeri bloğun son ifadesidir; `write` yazılan bayt sayısını verir.

```ruby
# kipler.rb — w sifirlar, a sonuna ekler
File.write("kip.txt", "bir\niki\n")

File.open("kip.txt", "a") { |f| f.puts "uc" }
puts File.readlines("kip.txt").size

donus = File.open("kip.txt", "w") { |f| f.write("tek\n") }
puts donus
puts File.readlines("kip.txt").size

File.open("kip.txt", "a") { |f| puts f.method(:puts).owner }
```

```
3
4
1
IO
```

İki satırlık dosyaya `"a"` ile bir satır eklenince sayı `3` oldu. `"w"` ile açılış dosyayı sıfırladı: blok `write` değerini, yani `4` baytı döndürdü ve satır sayısı `1`'e indi. `puts` yöntemi `IO` sınıfında tanımlıdır; yanıtlayan sınıftır. **KB60.** Ölçüm yalnız `"a"` ve `"w"` kipleriyle yapıldı; okuma ve yazma kipleri birlikte denenmedi.

## puts ve print Farkı

Dosyaya yazarken `puts` satır sonu ekler, `print` eklemez. Fark, yazılan içeriğin `inspect` çıktısında görünür.

```ruby
# yazim_farki.rb — puts satir sonu ekler, print eklemez
File.open("fark.txt", "w") do |f|
  f.puts "a"
  f.print "b"
  f.puts "c"
end
puts File.read("fark.txt").inspect
puts File.size("fark.txt")
File.open("fark.txt") { |f| puts f.method(:print).owner }
```

```
"a\nbc\n"
5
IO
```

Dosyada `a`, satır sonu, `b`, `c` ve yine satır sonu var; `b` ile `c` bitişik yazıldı. Toplam beş bayt. `print` de `IO` sınıfındadır; yanıtlayan sınıftır. **KB61.** İçerik ASCII dizgilerdi; çok baytlı karakterlerde bayt sayısı karakter sayısından ayrışır ve burada ölçülmedi.

## Var Olma ve Boyut

`File.exist?` bir yolun var olup olmadığını, `File.size` bayt boyutunu verir. Açık bir dosya nesnesinin kendi `size` yöntemi de vardır ve sahibi `File`'dır.

```ruby
# boyut.rb — var olma ve boyut
File.write("boyut.txt", "abcd")
puts File.exist?("boyut.txt")
puts File.exist?("yok.txt")
puts File.size("boyut.txt")
File.open("boyut.txt") do |f|
  puts f.size
  puts f.method(:size).owner
end
```

```
true
false
4
4
File
```

Var olan dosya için `true`, olmayan için `false` döndü. Boyut `4` bayttı ve açık nesne de aynı değeri verdi. Bu kez sahip `IO` değil `File`'dır: dosyaya özgü bilgi alt sınıfta durur, akış işleri üst sınıfta. **KB62.** Boş dosya ve silinmiş dosya ölçülmedi.

## Satır Satır ve Enumerable

`each_line` blok verilmezse bir yineleyici döndürür ve `chomp: true` satır sonlarını atar. Yineleyicinin `map` yöntemi `Enumerable` modülünden gelir. Okuma, dönüştürme, süzme ve yazma bir akış olarak bağlanabilir.

```ruby
# akis.rb — oku, map, select, yaz
File.write("girdi.txt", "elma\nkar\narmut\nay\n")

satirlar = []
File.open("girdi.txt") { |f| f.each_line(chomp: true) { |s| satirlar << s } }
puts satirlar.inspect

yineleyici = File.foreach("girdi.txt", chomp: true)
puts yineleyici.method(:map).owner

sonuc = yineleyici.map(&:upcase).select { |s| s.size > 3 }
yazilan = File.write("cikti.txt", sonuc.join("\n") + "\n")
puts yazilan
puts File.read("cikti.txt").inspect
```

```
["elma", "kar", "armut", "ay"]
Enumerable
11
"ELMA\nARMUT\n"
```

`each_line` dört satırı sondaki satır sonu olmadan verdi. `File.foreach` blok almadan çağrılınca bir yineleyici döndürdü ve `map` onun için `Enumerable` modülündedir; yanıtlayan modüldür. `upcase` sonrası `select` dört harften uzun olanları bıraktı: `ELMA` ve `ARMUT`. Yazılan `ELMA`, satır sonu, `ARMUT`, satır sonu on bir bayttır. **KB63.** Akış tek geçişli ve küçük bir girdiyle ölçüldü; büyük dosyada belleğe ne olduğu ölçülmedi.

## Standart Girdiyi Borudan Okumak

Standart girdi, programın dışarıdan satır aldığı akıştır ve `$stdin` ile okunur. Ders blokları etkileşimli girdi beklemez; bu yüzden girdi bir **boru (pipe)** ile verilir: bir komutun çıktısı, sonraki komutun girdisi olur.

```ruby
# oku.rb — standart girdiyi satir satir okur
ilk = $stdin.gets.chomp
kalan = $stdin.each_line.map(&:chomp)
puts ilk
puts kalan.inspect
puts $stdin.method(:gets).owner
```

```bash
# girdi.sh — oku.rb'yi borudan besler
printf 'bir\niki\nuc\n' | ruby oku.rb
```

```
bir
["iki", "uc"]
IO
```

`gets` ilk satırı okudu, `each_line` kalanları tüketti. `$stdin.gets` de `IO` sınıfındadır; dosyayı da klavyeyi de aynı sınıf okur. **KB64.** Girdi üç satırlık sabit bir dizgiydi; boş girdi ve çok büyük girdi ölçülmedi.

Aynı boru satır saymak için de kullanılır. `each_line` bloksuz çağrılınca bir yineleyici döndürür; `count` ona `Enumerable` modülünden gelir.

```ruby
# say.rb — standart girdideki satirlari sayar
puts $stdin.each_line.count
puts $stdin.method(:each_line).owner
puts $stdin.each_line.method(:count).owner
```

```bash
# say.sh — say.rb'yi borudan besler
printf 'a\nb\nc\nd\n' | ruby say.rb
```

```
4
IO
Enumerable
```

Dört satırlık girdi `4` olarak sayıldı. `each_line` yöntemi `IO` sınıfındadır, yineleyicinin `count` yöntemi ise `Enumerable` modülündedir; bu iki yanıtlayan aynı ifadede art arda çalışır. **KB65.** Girdi sabit ve dört satırlıktı; son satırı satır sonsuz biten girdi ölçülmedi.

## Sınırlayıcı Ölçüm

Bu dersin yanıtlayanı blok, ama bu cümle yarım kalırsa yanıltır: blok sonucu belirler, kaynağı temizleyen blok değildir. Kapatmayı bloklu `File.open` yöntemi üstlenir. Bunu ayırmak için bloğun içinde bir istisna fırlatılır. Dosya nesnesi bloğun dışında tutulur, istisna yakalanır ve ardından dosyanın durumu sorulur. Karşılaştırma için aynı istisna bloksuz açılmış bir dosyanın yanında fırlatılır.

```ruby
# istisna_kapanis.rb — blok istisna firlatsa da dosya kapanir
File.write("not.txt", "ilk satir\nikinci satir\n")

tutulan = nil
begin
  File.open("not.txt") do |dosya|
    tutulan = dosya
    raise "blok koptu"
  end
rescue => e
  puts e.class
end
puts tutulan.closed?

elle = File.open("not.txt")
begin
  raise "elle acik"
rescue => e
  puts e.class
end
puts elle.closed?
elle.close
puts elle.closed?
```

```
RuntimeError
true
RuntimeError
false
true
```

İlk durumda blok `RuntimeError` fırlattı, dal onu yakaladı ve dosya yine de kapalıydı (`true`). İkinci durumda aynı istisna bloksuz açılmış dosyanın yanında fırlatıldı ve dosya açık kaldı (`false`) ta ki elle `close` çağrılana kadar. Fark bloğun içeriğinde değil, kapatma sorumluluğunun yerindedir: bloklu `File.open`, bloğu bir `ensure` içinde koşturur ve ne olursa olsun dosyayı kapatır. Bu, önceki dersteki kaynak temizleme yapısının dilin kitaplığına yerleştirilmiş biçimidir. Sonucu blok belirler, kaynak temizliğini `File.open` üstlenir. **KB66.** Ölçüm `RuntimeError` ile yapıldı; blokta `break` ya da `throw` ile çıkış denenmedi.

## Özet

- `File.read`, `File.readlines` ve `File.foreach` dosyayı kendileri açıp kapatır; `File.write` yazılan bayt sayısını döndürür; olmayan bir dosyayı okumak `Errno::ENOENT` fırlatır.
- Bu dersin yanıtlayanı **blok**tur: aynı `File.open` iletisi bir blokla `"ilk satir"`, öteki blokla `2` verdi.
- Bloksuz `File.open` dosyayı açık bırakır; bloklu çağrıda blok bitince `closed?` `true` olur ve dönüş değeri bloğun değeridir.
- `gets`, `each_line` ve `$stdout.puts` `IO` sınıfında tanımlıdır; standart girdi bir borudan beslenerek okunur.
- `"w"` dosyayı sıfırlar, `"a"` sonuna ekler; `puts` satır sonu ekler, `print` eklemez; yineleyicinin `map` ve `count` yöntemleri `Enumerable` modülündedir.
- Sınırlayıcı ölçüm: blok istisna fırlatsa da dosya kapanır, çünkü kapatmayı blok değil `File.open` yöntemi yapar.

## Kurs Kapanışı

Kursun her dersi aynı soruyu sordu: bu iletiyi kim yanıtlıyor. Tablo, on iki dersin ölçtüğü iletiyi, o dersin yanıtlayanını ve sınırlayıcı ölçümünün söylediği şeyi yan yana koyar. Yanıtlayan sütunu her dersin `## Özet` bölümünde yazılı olandır.

| Ders | Ölçülen ileti | Yanıtlayan | Sınırlayıcı ölçüm |
|---|---|---|---|
| Ruby'nin Tasarım Felsefesi | `5.between?(1, 10)` | modül | `between?` `Comparable`'da, `<=>` alıcının sınıfında |
| Nesne Modeli Sezgisi | `5 + 3` | sınıf | `Integer.===` iletisini `Module` yanıtlar |
| Değişkenler ve Sabitler | `x = 5` | sözdizimi | `y += 1` atamadır, içindeki toplamayı `Integer` yanıtlar |
| Denetim Akışı | `(1..10) === 7` | sınıf | `case`, dal nesnesinin sınıfına sorar |
| Yöntemler | `format("%03d", 7)` | modül | üst düzey `def` `Object`'e yazılır ve özeldir |
| Semboller ve Dizgiler | `"ad".to_sym` | sınıf | sihirli yorum sahibi değiştirmez, dosya başına geçerlidir |
| Diziler ve Karma Yapılar | `Hash.new { 0 }[:x]` | blok | blok yalnız anahtar yokken yanıtlar |
| Bloklar | `sayilar.map { ... }` | blok | `each` iki blokla da `[1, 2]` verir, sahibi `Array` |
| `Enumerable` Modülü | `(1..5).each_slice(2)` | modül | `sum` aralıkta modülde, dizide `Array`'de |
| Proc ve Lambda | `->(n) { n * 2 }.call(3)` | sınıf | sahip aynı, fark `lambda?` durumunda |
| İstisnalar | `begin ... rescue ... end` | sözdizimi | dalın eşleşmesi `===` iletisiyle yapılır |
| Dosya ve Girdi/Çıktı | `File.open("not.txt") { ... }` | blok | kapatmayı blok değil yöntem yapar |

On iki dersin yanıtlayanı dağılımı: **4 sınıf · 3 modül · 3 blok · 2 sözdizimi**. Bu, çekirdeğin on iki gözleminin dağılımıyla aynıdır, çünkü çekirdek her ders için bir gözlem taşır. İki sonuç tablodan okunur. Birincisi, yanıtlayan çoğu zaman tek başına çalışmadı: sınırlayıcı ölçümlerin çoğu, dersin yanıtlayanının yanında başka bir yanıtlayanın da çalıştığını gösterdi. İkincisi, yanıtlayan sorusunun cevabı iletiye değil, iletinin alıcısına, verilen bloğa ve ifadenin biçimine bağlıdır. **KB67.** Tablo bu kursun on iki gözleminin dağılımını verir; Ruby'nin tamamının dağılımı hakkında bir iddia taşımaz.

Kurs burada kapanır. Ruby'de bir işlemin sonucunu üreten kod dört yerde durur: alıcının sınıfında, karıştırılmış bir modülde, çağıranın verdiği blokta ya da dilin kendi sözdiziminde. Bu kurs bu dört yeri yalnız **sonucu** ölçerek ayırdı; bir yöntemin neden belirli bir sınıfta ya da modülde bulunduğu sorusu açık kaldı. Sıradaki kursun konu alanı sınıf tanımı, kalıtım, modüller ve karışımlar, yöntem arama zinciri ve metaprogramlamadır; bu derslerde bugünkü ölçümlerin arkasındaki düzenek ele alınacaktır.
