【问题标题】:Ruby's File.open and the need for f.closeRuby 的 File.open 和 f.close 的需要
【发布时间】:2011-06-15 06:59:48
【问题描述】:

在大多数编程语言中,处理文件的流程是开放-使用-关闭,这是众所周知的。然而,我在 ruby​​ 代码中多次看到无与伦比的 File.open 调用,而且我在 ruby​​ 文档中找到了this gem of knowledge

I/O 流在被垃圾收集器声明时会自动关闭。

darkredandyellow 友好的 irc 处理这个问题:
[17:12] 是的,而且文件描述符的数量通常受操作系统限制
[17:29] 我假设你可以很容易地用完可用的文件描述符之前垃圾收集器清理。在这种情况下,您可能希望自己使用关闭它们。 “被垃圾收集器认领。”意味着 GC 在未来的某个时间点起作用。而且很贵。显式关闭文件的原因很多。

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

【问题讨论】:

  • 自析构函数被发明以来,你的“常识”已经过时了。
  • @meager: 析构函数是什么时候发明的?
  • 请注意:虽然文件描述符是有限的,但至少在 Linux 上,限制是相当高的。
  • @Linuxios :在我的 ubuntu12.04 $ ulimit -n => 1024 上,只有当你做一些简单的工作时它才会很高。坏习惯终有一天会出大问题!

标签: ruby file


【解决方案1】:
  1. 是的
  2. 如果您不这样做,或者有其他故障
  3. 见 2。

【讨论】:

    【解决方案2】:

    你应该总是在使用后关闭文件描述符,这也会刷新它。人们经常使用File.open 或带有块的等效方法来处理文件描述符的生命周期。例如:

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

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

    【讨论】:

    • 好点。我跟踪了一个不调用 File.close 的脚本的错误。因此,某些文件有时会丢失最后一行。
    • 优秀。我从来不知道这个把戏。在这方面很像 java-8。谢谢。
    【解决方案3】:

    我在 ruby​​ 代码中多次看到无与伦比的 File.open 调用

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

    有经验的 Ruby 专家要么显式关闭他们的文件,要么更习惯地使用 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 类定义了一个关闭文件的终结器。

    如果不是,那为什么选择呢?

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

    您根本无法预测何时垃圾收集器会运行。你甚至无法预测如果它会运行根本:如果你永远不会耗尽内存,垃圾收集器永远不会运行,因此终结器永远不会运行,因此文件永远不会关闭。

    【讨论】:

    • github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/… +23 (虽然它的 Kernel#open 主要用于它的 HTTP 端,但我使用本地文件路径参数达到了它,不过......;我仍在尝试找时间打补丁&request-pull),github.com/jnicklas/carrierwaveCtrl+f "File.open"(它是作为例子给出的,但是方式很糟糕......),还有其他几个我不记得的地方。由于我的项目中的稳定性要求,我对此问题感到不满..
    • 在这个例子中, raise 应该在救援块内吗?如果调用 raise 并且没有异常,这不会抛出运行时错误吗?
    • @JeffStorey:不错的收获! 17 个月未被注意到……
    • @JörgWMittag 现在还有 17 个月未修复:P 我想这里的重点是 ensurerescueraise 根本不需要。
    • 我认为没有rescue 就不能拥有ensure。而且您不能只是默默地吞下异常,您需要在关闭文件后将其传播给调用者。无论如何,请在 15 年 5 月再次提醒我:-D
    【解决方案4】:

    我们可以使用File.read()函数来读取ruby中的文件..... 比如,

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

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

    【讨论】:

      【解决方案5】:

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

      在没有关联块的情况下,File.open 是 ::new 的同义词。如果 给出可选代码块,它将作为参数传递打开的文件 并且File对象会在block的时候自动关闭 终止。块的值将从 File.open 返回。

      因此,会在区块终止时自动关闭 :D

      【讨论】:

        猜你喜欢
        • 2020-05-19
        • 1970-01-01
        • 2020-02-12
        • 2016-02-14
        • 1970-01-01
        • 2011-04-10
        • 2017-06-04
        • 1970-01-01
        • 2019-04-06
        相关资源
        最近更新 更多