Ruby'nin Dosyası.açık ve f.close'a duyulan ihtiyaç


92

Çoğu programlama dilinde, dosyalarla çalışma akışının açık-kullan-kapat olduğu yaygın bir bilgidir. Yine de Ruby kodlarında eşsiz File.open çağrılarında birçok kez gördüm ve dahası bu bilgi mücevherini ruby belgelerinde buldum :

G / Ç akışları, çöp toplayıcı tarafından talep edildiğinde otomatik olarak kapatılır.

darkredandyellow dostu irc konuyu ele alıyor:
[17:12] evet, ve ayrıca, dosya tanımlayıcıların sayısı genellikle işletim sistemi tarafından sınırlıdır
[17:29] Çöp toplayıcı temizlemeden önce kullanılabilir dosya tanımlayıcıların kolayca tükenebileceğini varsayıyorum yukarı. bu durumda, bunları kendiniz kapatmak isteyebilirsiniz. "çöp toplayıcı tarafından talep edildi." GC'nin gelecekte bir noktada hareket edeceği anlamına gelir. ve pahalıdır. dosyaları açıkça kapatmak için birçok neden.

  1. Açıkça kapatmamız gerekiyor mu
  2. Cevabınız evet ise, o zaman GC neden otomatik kapanır?
  3. Öyleyse neden seçenek?

1
Yıkıcılar icat edildiğinden beri 'ortak bilginiz' geçerliliğini yitirdi.
meagar

1
@meager: Yıkıcılar ne zaman icat edildi?
Andrew Grimm

Sadece bir not: Dosya tanımlayıcıları sınırlı olsa da, en azından Linux'ta sınır oldukça yüksektir.
Linuxios

1
@Linuxios: ubuntu12.04 cihazımda $ ulimit -n => 1024sadece basit bir iş yaptığınızda yüksek. Kötü alışkanlık bir gün büyük sorunlara neden olur!
HVNSweeting

Yanıtlar:


133

Ruby kodlarında birçok kez eşsiz File.openaramalar gördüm

Bir örnek verebilir misin? "Çoğu programlama dilinde, dosyalarla çalışma akışının açık-kullan-kapat" olduğu konusunda ortak bilgiye sahip olmayan yeni başlayanlar tarafından yazılan kodlarda görüyorum .

Deneyimli Rubyistler ya dosyalarını açıkça kapatırlar ya da daha deyimsel File.openolarak, dosyayı sizin için otomatik olarak kapatan blok biçimini kullanırlar . Uygulanması temelde şuna benzer:

def File.open(*args, &block)
  return open_with_block(*args, &block) if block_given?
  open_without_block(*args)
end

def File.open_without_block(*args)
  # do whatever ...
end

def File.open_with_block(*args)
  yield f = open_without_block(*args)
ensure
  f.close
end

Komut dosyaları özel bir durumdur. Komut dosyaları genellikle çok kısa çalışır ve o kadar az dosya tanımlayıcısı kullanır ki, onları kapatmak mantıklı değildir, çünkü komut dosyası çıkarken işletim sistemi onları yine de kapatacaktır.

Açıkça kapatmamız gerekiyor mu?

Evet.

Cevabınız evet ise, o zaman GC neden otomatik olarak kapanır?

Çünkü nesneyi topladıktan sonra, artık dosyayı kapatmanızın bir yolu yoktur ve böylece dosya tanımlayıcılarını sızdırırsınız.

Dosyaları kapatanın çöp toplayıcı olmadığını unutmayın. Çöp toplayıcı, bir nesneyi toplamadan önce sonlandırıcıları çalıştırır. Sadece çok olur Filesınıf dosyayı kapatır bir finalizer tanımlar.

Öyleyse neden seçenek?

Çünkü boşa harcanan bellek ucuzdur, ancak boşa giden dosya tanımlayıcıları değildir. Bu nedenle, bir dosya tanımlayıcısının ömrünü bir miktar bellek ömrüne bağlamak mantıklı değildir.

Çöp toplayıcının ne zaman çalışacağını tahmin edemezsiniz . Hatta tahmin edemez eğer o çalışacaktır hiç : bellek tükendi asla eğer, çöp toplayıcı çalıştırmak asla bu nedenle sonlandırıcı koşmak asla bu nedenle dosya kapatılacak asla.


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/… +23 (Çekirdek # açık olmasına ve öncelikle HTTP tarafı için kullanılmasına rağmen, ancak yine de yerel bir dosya yolu parametresiyle ona ulaştım. ..; yama ve istek-çekme için hala zaman bulmaya çalışıyorum), github.com/jnicklas/carrierwave Ctrl + f "File.open" (örnek olarak verilmiştir, ancak kötü bir şekilde ...) ve birkaç hatırlamadığım diğer yerler. Projelerimdeki istikrar gereksinimleri nedeniyle sorunla ilgili bir sorunum var ..
clyfe

3
Bu örnekte yükseltme, kurtarma bloğunun içinde olmalı mı? Bu, yükseltme çağrılırsa ve bir istisna yoksa bir çalışma zamanı hatası vermez mi?
Jeff Storey

@JeffStorey: İyi yakaladın! 17 ay fark edilmeden…
Jörg W Mittag

@ JörgWMittag ve şimdi 17 ay daha sabit değil: PI sanırım buradaki ana nokta ensure, rescueve raisehiç de gerekli değil.
KL-7 7

Sanırım ensureonsuz sahip olamazsın rescue. Ve istisnayı sessizce yutamazsınız, dosyayı kapattıktan sonra onu arayana iletmeniz gerekir. Her neyse, Mayıs '15'te tekrar hatırlat:
Jörg W Mittag

72

Her zaman kullanımdan sonra dosya tanımlayıcılarını kapatmalısınız, bu da onu temizleyecektir. Genellikle insanlar dosya tanımlayıcısının ömrünü işlemek için File.open veya eşdeğer yöntemi bloklarla kullanır. Örneğin:

File.open('foo', 'w') do |f|
    f.write "bar"
end

Bu örnekte dosya otomatik olarak kapatılır.


İyi bir nokta. File.close'u çağırmayan bir komut dosyasında bir hata izledim. Sonuç olarak, ara sıra bazı dosyalarda son satır eksik olacaktır.
Erwan Legrand

Muhteşem. Bu numarayı hiç bilmiyordum. Bu açıdan java-8'e çok benziyor. Teşekkür ederim.
sagneta

2

Göre http://ruby-doc.org/core-2.1.4/File.html#method-c-open

İlişkili bir blok olmadan, File.open :: new ile eşanlamlıdır. Opsiyonel kod bloğu verilirse, açılan dosya bir argüman olarak geçirilecek ve blok sona erdiğinde File nesnesi otomatik olarak kapatılacaktır. Bloğun değeri File.open'dan döndürülür.

Bu nedenle, blok sona erdiğinde otomatik olarak kapanacaktır : D


1
  1. Evet
  2. Yapmazsan ya da başka bir başarısızlık varsa
  3. Bkz. 2.

-3

File.read()Dosyayı Ruby'de okumak için işlevi kullanabiliriz ..... örneğin,

file_variable = File.read("filename.txt")

bu örnekte file_variableo dosyanın tam değeri olabilir ....

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.