File.open, open and IO.foreach in Ruby, what is the difference?

RubyFile Io

Ruby Problem Overview


All of the following API do the same thing: open a file and call a block for each line. Is there any preference we should use one than another?

File.open("file").each_line {|line| puts line}
open("file").each_line {|line| puts line}   
IO.foreach("file") {|line | puts line}

Ruby Solutions


Solution 1 - Ruby

There are important differences beetween those 3 choices.

File.open("file").each_line { |line| puts line }

  • File.open opens a local file and returns a file object
  • the file stays open until you call IO#close on it

open("file").each_line { |line| puts line }

Kernel.open looks at the string to decide what to do with it.

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/

In the second case the StringIO object returned by Kernel#open actually holds the content of http://google.com/. If Kernel#open returns a File object, it stays open untill you call IO#close on it.

IO.foreach("file") { |line| puts line }

  • IO.foreach opens a file, calls the given block for each line it reads, and closes the file afterwards.
  • You don't have to worry about closing the file.

File.read("file").each { |line| puts line }

You didn't mention this choice, but this is the one I would use in most cases.

  • File.read reads a file completely and returns it as a string.
  • You don't have to worry about closing the file.
  • In comparison to IO.foreach this makes it clear, that you are dealing with a file.
  • The memory complexity for this is O(n). If you know you are dealing with a small file, this is no drawback. But if it can be a big file and you know your memory complexity can be smaller than O(n), don't use this choice.

It fails in this situation:

 s= File.read("/dev/zero") # => never terminates
 s.each …

ri

ri is a tool which shows you the ruby documentation. You use it like this on your shell.

ri File.open
ri open
ri IO.foreach
ri File#each_line

With this you can find almost everything I wrote here and much more.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpierrotlefouView Question on Stackoverflow
Solution 1 - RubyjohannesView Answer on Stackoverflow