Pytanie Ruby's File.open i potrzeba f.close


Powszechnie wiadomo w większości języków programowania, że ​​przepływ pracy z plikami jest otwarty do użycia. Jednak widziałem wiele razy w rubinowych kodach niezrównane połączenia File.open, a ponadto znalazłem ten klejnot wiedzy w rubinowych dokumentach:

Strumienie We / Wy są automatycznie zamykane, gdy zostaną odebrane przez odśmiecacz.

darkredandyellow przyjazny irc wziąć na temat:
[17:12] tak, a także liczba deskryptorów plików jest zwykle ograniczona przez system operacyjny
[17:29] Zakładam, że możesz łatwo zabraknąć dostępnych deskryptorów plików przed Śmieciarz czyści. w takim przypadku możesz chcieć zamknąć je samodzielnie. "twierdził przez śmieciarza." oznacza, że ​​GC działa w pewnym momencie w przyszłości. i jest drogi. wiele powodów do jednoznacznego zamykania plików.

  1. Czy musimy wyraźnie zamknąć
  2. Jeśli tak, dlaczego GC jest automatycznie zamykany?
  3. Jeśli nie, dlaczego ta opcja?

76
2018-01-25 15:38


pochodzenie


Twoja "powszechna wiedza" była przestarzała od czasu wynalezienia destruktorów. - meagar♦
@meager: Kiedy wymyślono destruktory? - Andrew Grimm
Uwaga: Chociaż deskryptory plików są ograniczone, przynajmniej na Linuksie limit jest dość wysoki. - Linuxios
@Linuxios: na moim ubuntu12.04 $ ulimit -n => 1024 jest tylko wysoki, gdy wykonujesz jakąś prostą robotę. Zły nawyk spowoduje pewnego dnia duży problem! - HVNSweeting


Odpowiedzi:


Widziałem wiele razy w rubinowych kodach niedopasowanych File.open połączenia

Czy możesz dać przykład? Widzę to tylko w kodzie napisanym przez początkujących, którzy brak "powszechna wiedza w większości języków programowania, że ​​przepływ do pracy z plikami jest otwarty do użycia-zamknij".

Doświadczeni Rubyści jawnie zamykają swoje pliki lub, bardziej idiomatycznie, używają formy blokowej File.open, który automatycznie zamyka plik dla ciebie. Jego wdrożenie zasadniczo 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 są szczególnym przypadkiem. Skrypty zazwyczaj działają tak krótko i używają tak niewielu deskryptorów plików, że zamykanie ich nie ma sensu, ponieważ system operacyjny i tak je zamknie, gdy skrypt zostanie zamknięty.

Czy musimy wyraźnie zamknąć?

Tak.

Jeśli tak, dlaczego GC jest automatycznie zamykany?

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

Zauważ, że to nie garbage collecter zamyka pliki. Śmieciarz po prostu wykonuje jakiekolwiek finalizatory dla obiektu, zanim je zbierze. Tak się składa, że File klasa definiuje finalizator, który zamyka plik.

Jeśli nie, dlaczego ta opcja?

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

Po prostu nie możesz przewidzieć gdy Śmieciarz będzie działał. Nie możesz nawet przewidzieć gdyby będzie działać w ogóle: jeśli nigdy nie zabraknie pamięci, śmieciarz nigdy się nie uruchomi, dlatego finalizator nigdy się nie uruchomi, dlatego plik nigdy nie zostanie zamknięty.


113
2018-01-25 16:04



github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/... +23 (chociaż jego jądro # jest otwarte i używane przede wszystkim po stronie HTTP, ale doszedłem do niego z lokalnym parametrem ścieżki pliku, niemniej jednak ...; wciąż próbuję znaleźć czas na poprawkę i żądanie pobrania), github.com/jnicklas/carrierwave Ctrl + f "File.open" (jest podany jako przykład, ale w zły sposób ...) i kilka innych miejsc, których nie pamiętam. Mam wołowinę z problemem ze względu na wymogi stabilności w moich projektach. - clyfe
W tym przykładzie, należy podnieść się w bloku ratunkowym? Czy to nie spowoduje błędu runtime, jeśli podniesione zostanie wywołanie i nie ma wyjątku? - Jeff Storey
@JeffStorey: niezły haczyk! 17 miesięcy niezauważone ... - Jörg W Mittag
@ JörgWMittag, a teraz jeszcze 17 miesięcy nie ustalono: P Myślę, że głównym punktem jest tutaj ensure, rescue i raise w ogóle nie są konieczne. - KL-7
Myślę, że nie możesz ensure bez rescue. I nie możesz po prostu po cichu przełknąć wyjątku, musisz go przekazać dzwoniącemu, po zamknięciu pliku. W każdym razie, przypomnij mi jeszcze raz w maju '15 :-D - Jörg W Mittag


Zawsze powinieneś zamykać deskryptory plików po użyciu, co spowoduje ich przepłukanie. Często ludzie używają File.open lub równoważną metodą z blokami do obsługi czasu działania deskryptora pliku. Na przykład:

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

W tym przykładzie plik jest zamykany automatycznie.


62
2018-01-25 15:47



Słuszna uwaga. Śledziłem błąd w skrypcie, który nie wywołuje File.close. W rezultacie w niektórych plikach będzie brakować ostatniego wiersza. - Erwan Legrand
Wybitny. Nigdy nie znałem tej sztuczki. Podobnie jak java-8 w tym względzie. Dziękuję Ci. - sagneta


  1. tak
  2. W przypadku, gdy nie, lub jeśli wystąpi inny błąd
  3. Zobacz 2.

1
2018-01-25 15:40





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   opcjonalny blok kodu jest podany, jako argument zostanie przekazany otwarty plik   a obiekt File zostanie automatycznie zamknięty po bloku   kończy się. Wartość bloku zostanie zwrócona z File.open.

W związku z tym, zostanie automatycznie zamknięty po zakończeniu bloku :RE


1
2018-05-26 17:31





Możemy użyć File.read() funkcja do odczytu pliku w ruby ​​..... Jak na przykład,

file_variable = File.read("index.html")

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


-1
2018-01-10 12:09