Ruby'de bir dosyanın tamamını okumak için File.read("dosya.txt"), yazmak için File.write("dosya.txt", metin) yeterlidir. Daha fazla denetim istediğinizde File.open metodunu blokla kullanırsınız: blok bittiğinde dosya kendiliğinden kapanır. Büyük dosyaları satır satır işlemek için File.foreach ya da each_line, klasördeki dosyaları desenle bulmak için Dir.glob kullanılır.
File sınıfı IO sınıfından türer, bu yüzden read, write, readlines ve foreach gibi metotların ayrıntılı açıklaması IO belgesindedir. Aşağıdaki tüm örnekleri Ruby 4.0.9 ile geçici bir klasörde çalıştırdık. Ruby'ye yeniyseniz önce Ruby öğrenme rehberi sayfasına göz atabilirsiniz.
Dosyanın tamamını okumak ve yazmak

File.write dosyayı açar, veriyi yazar, kapatır ve yazılan bayt sayısını döndürür. Dosya yoksa oluşturulur, varsa içeriği silinip baştan yazılır. File.read ise dosyayı açıp tüm içeriği tek bir metin olarak döndürür:
File.write("notlar.txt", "Birinci satır\nİkinci satır\nÜçüncü satır\n") # => 48
icerik = File.read("notlar.txt")
icerik # => "Birinci satır\nİkinci satır\nÜçüncü satır\n"
icerik.encoding # => #<Encoding:UTF-8>
File.exist?("notlar.txt") # => true
File.exist?("yok.txt") # => falseDönüş değeri olan 48, Türkçe karakterler iki bayt tuttuğu için karakter sayısından büyüktür. Okunan metnin kodlaması varsayılan dış kodlamaya göre belirlenir; biz Ruby'yi -E UTF-8 ile çalıştırdık. Kodlamayı açıkça seçmeyi aşağıda ayrı başlıkta anlatıyoruz.
File.open ile blok kullanımı
File.open blok almadan çağrılırsa File nesnesi döndürür ve dosyayı sizin kapatmanız gerekir. Blokla çağrıldığında dosya nesnesini bloğa verir, blok bitince dosyayı kapatır ve bloğun son değerini döndürür. Blok içinde hata çıksa bile dosya kapanır. Bu yüzden çoğu durumda blok biçimi tercih edilir:
File.open("notlar.txt") do |f|
f.each_line(chomp: true) { |satir| puts satir }
end
# çıktı: Birinci satır
# çıktı: İkinci satır
# çıktı: Üçüncü satır
ilk = File.open("notlar.txt") { |f| f.gets }
ilk # => "Birinci satır\n"Blokların genel çalışma mantığı için Ruby blok ve yield yazısına bakabilirsiniz.
Açık dosyaya yazmak: puts, print ve write
Yazma modunda açtığınız dosya nesnesine üç farklı yolla veri gönderebilirsiniz. puts her argümandan sonra satır sonu ekler, print eklemez, write ise verdiğiniz argümanları olduğu gibi yazar ve toplam bayt sayısını döndürür. Blok biçiminde bu dönüş değeri File.open çağrısının sonucu olur:
File.open("liste.txt", "w") do |f|
f.puts "elma", "armut"
f.print "kiraz"
f.write "\n", "son"
end
File.read("liste.txt") # => "elma\narmut\nkiraz\nson"
File.open("liste.txt", "w") { |f| f.write("abc", "de") } # => 5Çok sayıda küçük yazma işlemi yapacaksanız dosyayı bir kez açıp blok içinde yazmak, her satır için File.write çağırmaktan daha mantıklıdır; çünkü File.write her çağrıda dosyayı yeniden açıp kapatır.
Satır satır okuma: each_line, foreach ve readlines
Üç yöntem de satırları ayırır ama bellekte tuttukları veri farklıdır. File.readlines tüm satırları bir dizi olarak döndürür; dosya küçükse pratiktir. File.foreach ve IO#each_line satırları teker teker bloğa verir, böylece dosyanın tamamı aynı anda bellekte durmaz. chomp: true seçeneği satır sonundaki \n karakterini atar:
File.readlines("notlar.txt", chomp: true)
# => ["Birinci satır", "İkinci satır", "Üçüncü satır"]
File.foreach("notlar.txt").with_index(1) { |s, i| puts "#{i}: #{s}" }
# çıktı: 1: Birinci satır
# çıktı: 2: İkinci satır
# çıktı: 3: Üçüncü satırFile.foreach blok almadan çağrıldığında bir Enumerator döndürür; yukarıda with_index bu sayede çalışıyor. Ayrıntı için Ruby Enumerator ve lazy yazısına bakın.
Dosya açma modları

File.open ve File.new ikinci argüman olarak bir mod alır. Varsayılan mod "r" (yalnızca okuma) dur. File belgesindeki tabloları şöyle özetleyebiliriz:
| Mod | Var olan dosyayı siler mi? | Okuma | Yazma |
|---|---|---|---|
| r | Hayır | Her yerden, baştan başlar | Hata |
| w | Evet | Hata | Her yere, baştan başlar |
| a | Hayır | Hata | Yalnızca sona |
| r+ | Hayır | Her yerden | Her yere |
| w+ | Evet | Her yerden | Her yere |
| a+ | Hayır | Her yerden | Yalnızca sona |
"r" ve "r+" olmayan bir dosya için kullanılamaz. Moda ek harfler de eklenebilir: "b" ikili veri (dış kodlama ASCII-8BIT olur, Windows'ta satır sonu dönüşümü yapılmaz), "t" metin verisi, "x" ise dosya zaten varsa hata veren oluşturma modu. Hiçbiri verilmezse akış metin olarak açılır.
File.open("gunluk.log", "w") { |f| f.puts "ilk kayıt" }
File.open("gunluk.log", "a") { |f| f.puts "ikinci kayıt" }
File.read("gunluk.log") # => "ilk kayıt\nikinci kayıt\n"
File.write("gunluk.log", "üçüncü kayıt\n", mode: "a")
File.readlines("gunluk.log").size # => 3
begin
File.open("olmayan.txt", "r")
rescue Errno::ENOENT => e
puts "#{e.class}: #{e.message}"
end
# çıktı: Errno::ENOENT: No such file or directory @ rb_sysopen - olmayan.txt
begin
File.open("gunluk.log", "wx")
rescue Errno::EEXIST => e
puts "#{e.class}: #{e.message}"
end
# çıktı: Errno::EEXIST: File exists @ rb_sysopen - gunluk.logDosya ve klasör sorguları, yol işlemleri
File sınıfının sınıf metotları dosya sistemini sorgulamak ve yolları parçalamak için kullanılır. File.exist? herhangi bir girdi için, File.file? normal dosya, File.directory? klasör için true döner. File.join parçaları ayraçla birleştirir. Klasör oluşturma ve silme için standart kütüphanedeki FileUtils modülü işinizi kolaylaştırır:
require "fileutils"
FileUtils.mkdir_p("proje/lib/alt")
File.write("proje/lib/a.rb", "")
File.write("proje/lib/alt/b.rb", "")
File.write("proje/oku.md", "")
File.directory?("proje/lib") # => true
File.file?("proje/oku.md") # => true
File.basename("proje/lib/a.rb") # => "a.rb"
File.basename("proje/lib/a.rb", ".rb") # => "a"
File.extname("proje/lib/a.rb") # => ".rb"
File.dirname("proje/lib/a.rb") # => "proje/lib"
File.join("proje", "lib", "a.rb") # => "proje/lib/a.rb"
Dir.children("proje").sort # => ["lib", "oku.md"]FileUtils.mkdir_p ara klasörleri de oluşturur. FileUtils.rm_rf ise bir klasörü içindekilerle birlikte siler ve hata vermez; bu yüzden yolu iki kez kontrol etmeden kullanmayın.
Dir.glob ile dosya bulmak
Dir.glob bir desen alır ve eşleşen girdilerin adlarını varsayılan olarak sıralı bir dizi halinde döndürür. Desenler düzenli ifade değildir; kabuk joker karakterlerine benzer kurallarla çalışır:
| Desen | Anlamı |
|---|---|
| * | Nokta ile başlamayan herhangi bir ad parçası |
| **/ | Alt klasörlere özyinelemeli iner |
| ? | Tek bir karakter |
| [a-z] | Kümedeki tek bir karakter, [^a-z] ile olumsuzlama |
| {rb,md} | Seçeneklerden biri |
| \ | Sonraki özel karakteri kaçışlar |
Dir.glob("proje/**/*.rb") # => ["proje/lib/a.rb", "proje/lib/alt/b.rb"]
Dir.glob("*.rb", base: "proje/lib") # => ["a.rb"]
FileUtils.rm_rf("proje")
Dir.exist?("proje") # => falsebase: verdiğinizde desen o klasöre göre çözülür ve sonuçlara klasör adı eklenmez. Nokta ile başlayan gizli dosyalar * ile eşleşmez; bunlar için belge File::FNM_DOTMATCH bayrağını ya da {*,.*} desenini öneriyor. sort: false ile sıralamayı kapatabilirsiniz.
Pathname: nesne yönelimli yollar
Pathname, bir dosya ya da klasörün adını temsil eder, dosyanın kendisini değil. Değiştirilemez bir nesnedir ve File, FileTest ile Dir ve FileUtils metotlarının bir kısmını tek arayüzde toplar. Ruby 4.0 NEWS dosyasına göre Pathname artık çekirdek sınıf; denememizde require yazmadan çalıştı:
yol = Pathname.new("proje") / "lib" / "ana.rb"
yol # => #<Pathname:proje/lib/ana.rb>
yol.basename # => #<Pathname:ana.rb>
yol.extname # => ".rb"
yol.dirname # => #<Pathname:proje/lib>
yol.to_s # => "proje/lib/ana.rb"
Pathname("notlar.txt").read.lines.first # => "Birinci satır\n"Kodlama seçimi: Türkçe karakterler ve BOM
Okuduğunuz dosya UTF-8 değilse kodlamayı encoding: seçeneğiyle ya da mod metnine iki nokta ile ekleyerek belirtirsiniz. Tek kodlama verirseniz metin o kodlamayla etiketlenir; "dış:iç" biçiminde iki kodlama verirseniz okunan veri dış kodlamadan iç kodlamaya dönüştürülür. "BOM|UTF-8" ise dosyanın başındaki BOM işaretini algılayıp atar:
File.binwrite("latin.txt", "\xE7ay".b) # ISO-8859-9 ile "çay"
File.read("latin.txt", encoding: "ISO-8859-9") # => "\xE7ay"
File.read("latin.txt", encoding: "ISO-8859-9:UTF-8") # => "çay"
File.read("latin.txt", mode: "rb").encoding # => #<Encoding:BINARY (ASCII-8BIT)>
File.write("bomlu.txt", "\uFEFFmerhaba")
File.read("bomlu.txt").bytesize # => 10
File.read("bomlu.txt", mode: "r:BOM|UTF-8") # => "merhaba"İlk okumada çıktı "\xE7ay" görünür, çünkü Ruby baytı ISO-8859-9 olarak etiketler ama dönüştürmez. Kodlama konusunun tamamı için Ruby encoding ve Türkçe karakter yazısına bakın.
Ruby 4.0 ile değişen bir davranış
NEWS dosyasına göre IO sınıf metotları ve Kernel#open, başında | olan bir adla artık süreç başlatmıyor; bu kullanımdan kaldırılmış davranış 4.0 ile tamamen silindi. Böyle bir ad artık sıradan bir dosya yolu gibi ele alınır. Windows üzerindeki denememizde şu hata alındı:
begin
File.read("|echo merhaba")
rescue => e
puts "#{e.class}: #{e.message}"
end
# çıktı: Errno::EINVAL: Invalid argument @ rb_sysopen - |echo merhabaKomut çalıştırmanız gerekiyorsa IO belgesinde anlatılan IO.popen metodunu kullanın. Linux üzerinde hata sınıfı farklı olabilir; önemli olan, komutun artık çalışmamasıdır.
Sık yapılan hatalar

- Blok kullanmadan
File.opençağırıpcloseunutmak. Kapatılmış bir dosyadan okumak iseIOError: closed streamverir. - Ekleme yapmak isterken
"w"kullanıp dosyayı silmek. - Çok büyük bir log dosyasını
File.readile belleğe almak; satır satır işlemek içinFile.foreachdaha uygundur. - Windows'ta ikili dosyayı metin modunda okumak. IO belgesi, metin modunun Windows'ta bazı özel baytlarda okumayı erken bitirebileceğini belirtiyor; tüm baytlar için
File.binreadönerilir. - Kodlamayı belirtmeden farklı kodlamalı bir dosyayı okuyup Türkçe karakterleri bozuk görmek.
Sık Sorulan Sorular
File.read ile IO.read arasında fark var mı?
File, IO sınıfının alt sınıfı olduğu için File.read aslında IO'nun sınıf metodunu kullanır. Dosya yolu verdiğiniz sürece ikisi aynı işi yapar.
Dosya var mı diye nasıl kontrol ederim?
File.exist?(yol) kullanın. Yalnızca normal dosya mı diye bakmak için File.file?, klasör için File.directory? ya da Dir.exist? uygundur.
Bir klasördeki tüm .rb dosyalarını nasıl listelerim?
Sadece o klasör için Dir.glob("klasor/*.rb"), alt klasörler dahil Dir.glob("klasor/**/*.rb") yazın.
CSV dosyalarını nasıl okurum?
CSV için ayrı bir kütüphane vardır; NEWS'e göre csv Ruby 4.0'da paketlenmiş gem olarak geliyor. Format kurallarını CSV formatı ve JSON dönüşümü yazısında anlattık; JSON dosyaları için Ruby JSON kullanımı yazısına bakabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Ruby öğrenme rehberi · Ruby JSON kullanımı · Ruby encoding ve UTF-8 · Ruby hata yönetimi · Ruby 4.0 yenilikleri · Linux nedir?