Ответ 1
Между этими тремя выборами существуют важные различия.
File.open("file").each_line { |line| puts line }
-
File.open
открывает локальный файл и возвращает файл-объект - файл остается открытым до тех пор, пока вы не назовете
IO#close
на нем
open("file").each_line { |line| puts line }
Kernel.open
смотрит на строку, чтобы решить, что с ней делать.
open(".irbrc").class # => File
open("http://google.com/").class # => StringIO
File.open("http://google.com/") # => Errno::ENOENT: No such file or directory - http://google.com/
Во втором случае объект StringIO
, возвращаемый Kernel#open
, фактически содержит содержимое http://google.com/. Если Kernel#open
возвращает объект File
, он остается открытым до тех пор, пока вы не назовете IO#close
на нем.
IO.foreach("file") { |line| puts line }
-
IO.foreach
открывает файл, вызывает данный блок для каждой строки, которую он читает, и закрывает файл впоследствии. - Вам не нужно беспокоиться о закрытии файла.
File.read("file").each { |line| puts line }
Вы не упомянули об этом выборе, но это тот, который я использовал бы в большинстве случаев.
-
File.read
полностью читает файл и возвращает его как строку. - Вам не нужно беспокоиться о закрытии файла.
- По сравнению с
IO.foreach
это дает понять, что вы имеете дело с файлом. - Сложность памяти для этого - O (n). Если вы знаете, что имеете дело с небольшим файлом, это не является недостатком. Но если это может быть большой файл, и вы знаете, что ваша сложность памяти может быть меньше O (n), не используйте этот выбор.
В этой ситуации это не удается:
s= File.read("/dev/zero") # => never terminates
s.each …
п
ri - инструмент, который показывает вам рубиновую документацию. Вы используете его так же, как на своей оболочке.
ri File.open
ri open
ri IO.foreach
ri File#each_line
С этим вы можете найти почти все, что я написал здесь, и многое другое.