Ruby的File.open和对f.close的需求


92

在大多数编程语言中,众所周知,处理文件的流程是开放使用关闭的。但是我在ruby代码中多次看到无与伦比的File.open调用,而且我在ruby文档中发现了这一知识宝典:

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

darkredandyellow友好的irc解决了这个问题:
[17:12]是的,而且,文件描述符的数量通常受操作系统限制
[17:29]我假设您可以在垃圾收集器清理之前很容易用完可用的文件描述符向上。在这种情况下,您可能要自己使用关闭它们。“被垃圾收集者宣称。” 表示GC在将来的某个时候起作用。而且很贵 显式关闭文件的很多原因。

  1. 我们是否需要明确关闭
  2. 如果是,那么GC为什么会自动关闭?
  3. 如果没有,那为什么要选择呢?

1
自从析构函数发明以来,您的“常识​​”已经过时了。
meagar

1
@meager:析构函数是什么时候发明的?
安德鲁·格林

请注意:虽然文件描述符受到限制,但至少在Linux上,限制是相当高的。
Linuxios 2012年

1
@Linuxios:在我的ubuntu12.04上$ ulimit -n => 1024,仅做一些简单的工作就很高。坏习惯有一天会引起大问题!
HVNSweeting

Answers:


133

我在红宝石代码中多次看到无与伦比的File.open呼叫

能给我举个例子吗?我只在新手编写的代码中看到过这些新手,他们缺乏 “大多数编程语言中的常识,即处理文件的流程是开放使用-关闭”。

经验丰富的Rubyist要么明确关闭文件,要么更习惯于使用的块形式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

脚本是一种特殊情况。脚本通常运行时间很短,并且使用的文件描述符很少,以至于根本无法关闭它们,因为无论如何,脚本退出时操作系统都会关闭它们。

我们需要显式关闭吗?

是。

如果是,那么GC为什么会自动关闭?

因为在收集了对象之后,您再也无法关闭文件,因此您将泄漏文件描述符。

请注意,关闭文件的不是垃圾收集器。垃圾收集器在收集对象之前仅对对象执行任何终结器。碰巧的是File该类定义了一个终结器来关闭文件。

如果没有,那为什么要选择呢?

因为浪费的内存很便宜,但是浪费的文件描述符却不是。因此,将文件描述符的生存期与某些内存块的生存期联系起来是没有意义的。

你根本无法预测,当垃圾收集器将运行。你甚至不能预测,如果它将运行在所有的:如果你从来没有的内存用完,垃圾收集器将永远不会运行,因此终结永远不会运行,因此该文件将永远不会被关闭。


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/…+23(尽管它的Kernel#open并主要用于HTTP端,但是尽管如此,我还是使用了本地文件路径参数来实现它。 ..;我仍在尝试寻找时间进行补丁和请求拉),github.com/jnicklas/carrierwave Ctrl + f“ File.open”(作为示例,但以一种不好的方式……),还有几个我不记得的其他地方。由于项目的稳定性要求,我遇到了问题
。.– clyfe

3
在这个例子中,应该在救援箱内抬起吗?如果调用了raise并且没有异常,这是否会引发运行时错误?
杰夫·斯托里

@JeffStorey:不错!17个月被人忽略,
约尔格W¯¯米塔格

@JörgWMittag现在17个月以上没有固定的:PI猜测这里的要点是ensurerescueraise是没有必要的。
KL-

我想你不能ensure没有rescue。而且,您不能只是默默地吞下该异常,还需要在关闭文件后将其传播给调用方。不管怎样,再次提醒我在五月'15 :-D
约尔格W¯¯米塔格

71

使用后,您应始终关闭文件描述符,这也会刷新它。人们通常将File.open或等效方法与块一起使用来处理文件描述符寿命。例如:

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

在该示例中,文件自动关闭。


好点子。我跟踪到一个不调用File.close的脚本的错误。结果,有时某些文件中最后一行将丢失。
Erwan Legrand

优秀。我从来不知道这个把戏。在这方面很像java-8。谢谢。
sagneta '16


1
  1. 如果您不这样做,或者出现其他故障
  2. 见2。

-3

我们可以使用该File.read()函数读取红宝石文件.....,例如,

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

在此示例中,file_variable可以具有该文件的完整值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.