Ruby File.open и необходимость в f.close

Общеизвестно, что в большинстве языков программирования поток для работы с файлами открыт-закрывается. Тем не менее, я видел много раз в рубиновых кодах непревзойденные вызовы File.open, и более того, я нашел этот камень знаний в документах ruby:

Потоки ввода/вывода автоматически закрываются, когда они утверждаются сборщиком мусора.

darkredandyellow дружественный irc возьмется за проблему:
[17:12] да, а также количество файловых дескрипторов обычно ограничено ОС
[17:29] Я предполагаю, что вы можете легко исчерпать доступные дескрипторы файлов, прежде чем сборщик мусора очистится. в этом случае вы можете использовать их сами. "заявленный сборщиком мусора". означает, что ГК действует в какой-то момент в будущем. и это дорого. много причин для явного закрытия файлов.

  • Нужно ли явно закрывать
  • Если да, то почему GC автоклинирует?
  • Если нет, то почему опция?

Ответ 1

Я видел много раз в рубиновых кодах непревзойденные File.open звонки

Можете ли вы привести пример? Я только когда-либо вижу это в коде, написанном новичками, которым не хватает "общих знаний на большинстве языков программирования, что поток для работы с файлами открыт-используется-закрывается".

Опытные рубисты либо явно закрывают свои файлы, либо более идиоматично используют блочную форму File.open, которая автоматически закрывает файл для тебя. Его реализация в основном выглядит примерно так:

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

Скрипты - это особый случай. Скрипты обычно работают так короткими и используют так мало дескрипторов файлов, что просто не имеет смысла их закрывать, так как операционная система все равно закроет их, когда выйдет script.

Нужно ли явно закрывать?

Да.

Если да, то почему GC автоклинирует?

Поскольку после того, как он собрал объект, вам больше не удастся закрыть файл, и, следовательно, вы будете утечка дескрипторов файлов.

Обратите внимание, что это не сборщик мусора, который закрывает файлы. Сборщик мусора просто выполняет любые финализаторы для объекта, прежде чем он его собирает. Так получилось, что класс File определяет финализатор, который закрывает файл.

Если нет, то почему опция?

Потому что потерянная память дешевая, но потерянные файловые дескрипторы - нет. Поэтому нет смысла связывать время жизни файлового дескриптора с временем жизни некоторого фрагмента памяти.

Вы просто не можете предсказать, когда будет запущен сборщик мусора. Вы даже не можете предсказать, будет ли он работать вообще: если у вас никогда не закончится память, сборщик мусора никогда не запустится, поэтому финализатор никогда не запустится, поэтому файл никогда не будет закрыт.

Ответ 2

Вы должны всегда закрывать дескрипторы файлов после использования, которые также будут скрыты. Часто люди используют File.open или эквивалентный метод с блоками для обработки жизненного цикла дескриптора файла. Например:

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

В этом примере файл автоматически закрывается.

Ответ 3

  • Да
  • Если вы этого не сделали, или если есть другие сбои
  • См. 2.

Ответ 4

Мы можем использовать функцию File.read() для чтения файла в рубине..... например,

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

в этом примере file_variable может иметь полное значение этого файла....

Ответ 5

Согласно http://ruby-doc.org/core-2.1.4/File.html#method-c-open

Без связанного блока File.open является синонимом для:: new. Если предоставляется дополнительный блок кода, он будет передан открытый файл в качестве аргумента и объект File будет автоматически закрыт, когда блок завершается. Значение блока будет возвращено из File.open.

Следовательно, автоматически закрывается, когда блок завершается: D