Ruby's File.open i potrzeba f.close

92

W większości języków programowania powszechnie wiadomo, że praca z plikami przebiega w trybie open-use-close. Jednak wiele razy widziałem w kodach ruby ​​niezrównane wywołania File.open, a ponadto znalazłem ten klejnot wiedzy w dokumentach ruby:

Strumienie we / wy są automatycznie zamykane, gdy są zajęte przez moduł odśmiecania pamięci.

darkredandyellow przyjazny irc zajmuje się problemem:
[17:12] tak, a także liczba deskryptorów plików jest zwykle ograniczona przez system operacyjny
[17:29] Zakładam, że można łatwo zabraknąć dostępnych deskryptorów plików, zanim garbage collector wyczyści w górę. w takim przypadku możesz użyć zamknij je samodzielnie. „zgłoszony przez śmieciarza”. oznacza, że ​​GC zacznie działać w pewnym momencie w przyszłości. i jest drogi. wiele powodów do jawnego zamykania plików.

  1. Czy musimy wyraźnie zamknąć
  2. Jeśli tak, to dlaczego GC automatycznie się zamyka?
  3. Jeśli nie, to po co?
clyfe
źródło
1
Wasza „powszechna wiedza” stała się nieaktualna od czasu wynalezienia destruktorów.
meagar
1
@meager: Kiedy wynaleziono destruktory?
Andrew Grimm,
Uwaga: chociaż deskryptory plików są ograniczone, przynajmniej w Linuksie limit jest dość wysoki.
Linuxios
1
@Linuxios: na moim ubuntu12.04 $ ulimit -n => 1024jest wysoki tylko wtedy, gdy wykonujesz prostą pracę. Zły nawyk pewnego dnia spowoduje duży problem!
HVNSweeting,

Odpowiedzi:

133

Widziałem wiele razy w kodach ruby ​​niezrównane File.openpołączenia

Czy możesz podać przykład? Widzę to tylko w kodzie napisanym przez początkujących, którzy nie mają „powszechnej wiedzy w większości języków programowania, że ​​przepływ pracy z plikami jest otwarty-użyj-zamknij”.

Doświadczeni rubiniści albo jawnie zamykają swoje pliki, albo, bardziej idiomatycznie, używają formy blokowej File.open, która automatycznie zamyka plik za Ciebie. Jego implementacja w zasadzie wygląda mniej więcej tak:

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

Skrypty to szczególny przypadek. Skrypty zazwyczaj działają tak krótko i używają tak niewielu deskryptorów plików, że po prostu nie ma sensu ich zamykać, ponieważ system operacyjny i tak je zamknie, gdy skrypt zakończy działanie.

Czy musimy wyraźnie zamknąć?

Tak.

Jeśli tak, to dlaczego GC automatycznie się zamyka?

Ponieważ po zebraniu obiektu nie ma już możliwości zamknięcia pliku, a tym samym wyciekułoby deskryptory plików.

Zauważ, że to nie garbage collector zamyka pliki. Moduł odśmiecania pamięci po prostu wykonuje finalizatory dla obiektu, zanim go zbierze. Tak się składa, że Fileklasa definiuje finalizator, który zamyka plik.

Jeśli nie, to po co?

Ponieważ zmarnowana pamięć jest tania, ale zmarnowane deskryptory plików nie. Dlatego nie ma sensu wiązać czasu życia deskryptora pliku z czasem życia jakiegoś fragmentu pamięci.

Po prostu nie można przewidzieć, kiedy będzie działać odśmiecacz. Nie można jeszcze przewidzieć, czy to będzie działać w ogóle : jeśli nigdy nie zabraknie pamięci, garbage collector nigdy nie zabraknie, dlatego finalizator nigdy nie zabraknie, więc plik nigdy nie zostanie zamknięta.

Jörg W Mittag
źródło
1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/ ... +23 (chociaż jego Kernel # jest otwarty i używany głównie po stronie HTTP, ale mimo wszystko dotarłem do niego z parametrem lokalnej ścieżki pliku. ..; Wciąż staram się znaleźć czas na poprawkę i żądanie-pull), github.com/jnicklas/carrierwave Ctrl + f "File.open" (jest to podane jako przykład, ale w zły sposób ...) i kilka inne miejsca, których nie pamiętam. Mam problem z tym problemem ze względu na wymagania dotyczące stabilności w moich projektach ..
clyfe
3
W tym przykładzie, czy podniesienie powinno znajdować się wewnątrz bloku ratunkowego? Czy nie spowoduje to po prostu wyświetlenia błędu w czasie wykonywania, jeśli zostanie wywołane podbicie i nie ma wyjątku?
Jeff Storey,
@JeffStorey: niezły chwyt! 17 miesięcy niezauważone…
Jörg W Mittag
@ JörgWMittag a teraz 17 więcej miesięcy nie naprawiono: PI domyślić głównym punktem tutaj jest ensure, rescuei raisenie są w ogóle konieczne.
KL-7 7
Myślę, że nie możesz mieć ensurebez rescue. I nie możesz po prostu cicho połknąć wyjątku, musisz go przekazać wywołującemu po zamknięciu pliku. W każdym razie, przypomnij mi ponownie w maju '15 :-D
Jörg W Mittag
72

Po użyciu należy zawsze zamknąć deskryptory plików, co również spowoduje jego opróżnienie. Często ludzie używają File.open lub równoważnej metody z blokami do obsługi okresu istnienia deskryptora pliku. Na przykład:

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

W tym przykładzie plik jest zamykany automatycznie.

Tonttu
źródło
Słuszna uwaga. Wyśledziłem błąd w skrypcie, który nie wywołuje File.close. W rezultacie w niektórych plikach od czasu do czasu brakuje ostatniej linii.
Erwan Legrand
Wybitny. Nigdy nie znałam tej sztuczki. Podobnie jak java-8 pod tym względem. Dziękuję Ci.
sagneta
2

Według http://ruby-doc.org/core-2.1.4/File.html#method-c-open

Bez powiązanego bloku File.open jest synonimem :: new. Jeśli podano opcjonalny blok kodu, zostanie przekazany otwarty plik jako argument, a obiekt File zostanie automatycznie zamknięty po zakończeniu bloku. Wartość bloku zostanie zwrócona z File.open.

Dlatego zostanie automatycznie zamknięty po zakończeniu blokady : D

skozz
źródło
1
  1. tak
  2. Jeśli tego nie zrobisz lub jeśli wystąpi inna awaria
  3. Patrz 2.
Satya
źródło
-3

Możemy użyć File.read()funkcji do odczytania pliku w Rubim ..... takiej jak,

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

w tym przykładzie file_variablemoże mieć pełną wartość tego pliku ....

Kumar KS
źródło