Ruby 的文件,打开,需要 f.close

在大多数编程语言中,处理文件的流程是打开-使用-关闭的,这是常识。然而,我在 Ruby 编码中看到了很多不匹配的 File.open 调用,而且我还在 Ruby docs 中发现了 知识的宝石:

当垃圾收集器声明 I/O 流时,它们将自动关闭。

爱尔兰共和军(IRC)对这个问题采取了友好的态度:
[17:12]是的,而且,文件描述符的数量通常受到操作系统的限制
[17:29]我假设您可以很容易地用完垃圾收集器清理的可用文件描述符 之前。在这种情况下,您可能需要自己关闭它们。“被垃圾收集者认领”意味着 GC 将在未来某个时刻发挥作用。而且很贵。显式关闭文件的原因有很多。

  1. 我们需要明确关闭
  2. 如果是,那为什么 GC 会自动关闭?
  3. 如果没有,为什么选择?
75228 次浏览
  1. Yes
  2. In case you don't, or if there is some other failure
  3. See 2.

You should always close file descriptors after use, that will also flush it. Often people use File.open or equivalent method with blocks to handle file descriptor lifetime. For example:

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

In that example the file is closed automatically.

I saw many times in ruby codes unmatched File.open calls

Can you give an example? I only ever see that in code written by newbies who lack the "common knowledge in most programming languages that the flow for working with files is open-use-close".

Experienced Rubyists either explicitly close their files, or, more idiomatically, use the block form of File.open, which automatically closes the file for you. Its implementation basically looks something like like this:

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

Scripts are a special case. Scripts generally run so short, and use so few file descriptors that it simply doesn't make sense to close them, since the operating system will close them anyway when the script exits.

Do we need to explicitly close?

Yes.

If yes then why does the GC autoclose?

Because after it has collected the object, there is no way for you to close the file anymore, and thus you would leak file descriptors.

Note that it's not the garbage collector that closes the files. The garbage collector simply executes any finalizers for an object before it collects it. It just so happens that the File class defines a finalizer which closes the file.

If not then why the option?

Because wasted memory is cheap, but wasted file descriptors aren't. Therefore, it doesn't make sense to tie the lifetime of a file descriptor to the lifetime of some chunk of memory.

You simply cannot predict when the garbage collector will run. You cannot even predict if it will run at all: if you never run out of memory, the garbage collector will never run, therefore the finalizer will never run, therefore the file will never be closed.

We can use the File.read() function to read the file in ruby..... such as,

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

in this example file_variable can have the full value of that file....

According to http://ruby-doc.org/core-2.1.4/File.html#method-c-open

With no associated block, File.open is a synonym for ::new. If the optional code block is given, it will be passed the opened file as an argument and the File object will automatically be closed when the block terminates. The value of the block will be returned from File.open.

Therefore, will automatically be closed when the block terminates :D