Ruby 当引用由其他对象持有时,如何确保关闭文件

Ruby 当引用由其他对象持有时,如何确保关闭文件,ruby,nokogiri,Ruby,Nokogiri,在Ruby中,当对打开文件的引用传递给另一个对象时,如以下代码所示,我是否需要将另一个对象引用包装在“begin/sure”块中,以确保关闭非托管资源,还是有其他方法 @doc = Nokogiri::XML(File.open("shows.xml")) @doc.xpath("//character") # => ["<character>Al Bundy</character>", # "<character>Bud Bundy</c

在Ruby中,当对打开文件的引用传递给另一个对象时,如以下代码所示,我是否需要将另一个对象引用包装在“
begin
/
sure
”块中,以确保关闭非托管资源,还是有其他方法

@doc = Nokogiri::XML(File.open("shows.xml"))

@doc.xpath("//character")
# => ["<character>Al Bundy</character>",
#    "<character>Bud Bundy</character>",
#    "<character>Marcy Darcy</character>",
#    "<character>Larry Appleton</character>",
#    "<character>Balki Bartokomous</character>",
#    "<character>John "Hannibal" Smith</character>",
#    "<character>Templeton "Face" Peck</character>",
#    "<character>"B.A." Baracus</character>",
#    "<character>"Howling Mad" Murdock</character>"]
@doc=Nokogiri::XML(File.open(“shows.XML”))
@doc.xpath(“//字符”)
#=>[“邦迪”,
#“巴德邦迪”,
#“玛西·达西”,
#“拉里·阿普尔顿”,
#“巴尔基·巴托科莫斯”,
#“约翰·汉尼拔·史密斯”,
#“坦普顿”脸“派克”,
#“B.A.“巴拉卡斯”,
#“怒吼狂”默多克“]

我相信Nokogiri会在读取文件后立即关闭该文件,但是为了安全起见,如何替换
文件。用
文件打开
。读取


不,正如铁皮人指出的,Nokogiri在读取文件句柄后不会关闭它。正确的处理方法仍然是:

doc = Nokogiri::XML File.read("shows.xml")

一般来说,如果没有其他文件试图写入,并且您的程序不是一个长期运行的应用程序,那么不必担心打开一个文件。Ruby将在文件关闭并退出时关闭该文件。(我怀疑操作系统在看到文件打开时也会这样做,但如果不进入低级调试器或深入操作系统代码,就很难进行测试。)

如果您对此感到担忧,我建议您使用
File.open
的块形式,因为当您的代码退出块时,它会自动关闭文件:

require 'nokogiri'

doc = ''
File.open('./test.html', 'r') do |fi|
  doc = Nokogiri::HTML(fi)
end

puts doc.to_html

因为我很好奇,也一直很好奇,所以我做了一个小测试。我将一些HTML保存到一个名为“test.HTML”的文件中,并在IRB中运行了以下内容:

test.rb(main):001:0> require 'nokogiri'
=> true
test.rb(main):002:0> page = File.open('test.html', 'r')
=> #<File:test.html>
test.rb(main):003:0> page.eof?
=> false
test.rb(main):004:0> page.closed?
=> false
test.rb(main):005:0> doc = Nokogiri::HTML(page)
=> #<Nokogiri::HTML::Document:0x3fc10149bc98 name="document" children=[#<Nokogiri::XML::DTD:0x3fc10149b6f8 name="html">, #<Nokogiri::XML::Element:0x3fc10149ef60 name="html" children=[#<Nokogiri::XML::Element:0x3fc10149ed58 name="head" children=[#<Nokogiri::XML::Element:0x3fc10149eb50 name="title" children=[#<Nokogiri::XML::Text:0x3fc10149e948 "Example Domain">]>, #<Nokogiri::XML::Element:0x3fc10149e740 name="meta" attributes=[#<Nokogiri::XML::Attr:0x3fc10149e6dc name="charset" value="utf-8">]>, #<Nokogiri::XML::Element:0x3fc10149e218 name="meta" attributes=[#<Nokogiri::XML::Attr:0x3fc10149e1b4 name="http-equiv" value="Content-type">, #<Nokogiri::XML::Attr:0x3fc10149e1a0 name="content" value="text/html; charset=utf-8">]>, #<Nokogiri::XML::Element:0x3fc10149da98 name="meta" attributes=[#<Nokogiri::XML::Attr:0x3fc10149da34 name="name" value="viewport">, #<Nokogiri::XML::Attr:0x3fc10149da20 name="content" value="width=device-width, initial-scale=1">]>, #<Nokogiri::XML::Element:0x3fc10149d318 name="style" attributes=[#<Nokogiri::XML::Attr:0x3fc10149d2b4 name="type" value="text/css">] children=[#<Nokogiri::XML::CDATA:0x3fc1014a0dd8 "\n\tbody {\n\t\tbackground-color: #f0f0f2;\n\t\tmargin: 0;\n\t\tpadding: 0;\n\t\tfont-family: \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n\n\t}\n\tdiv {\n\t\twidth: 600px;\n\t\tmargin: 5em auto;\n\t\tpadding: 3em;\n\t\tbackground-color: #fff;\n\t\tborder-radius: 1em;\n\t}\n\ta:link, a:visited {\n\t\tcolor: #38488f;\n\t\ttext-decoration: none;\n\t}\n\t@media (max-width: 600px) {\n\t\tbody {\n\t\t\tbackground-color: #fff;\n\t\t}\n\t\tdiv {\n\t\t\twidth: auto;\n\t\t\tmargin: 0 auto;\n\t\t\tborder-radius: 0;\n\t\t\tpadding: 1em;\n\t\t}\n\t}\n\t">]>]>, #<Nokogiri::XML::Element:0x3fc1014a0aa4 name="body" children=[#<Nokogiri::XML::Text:0x3fc1014a089c "\n">, #<Nokogiri::XML::Element:0x3fc1014a07c0 name="div" children=[#<Nokogiri::XML::Text:0x3fc1014a05b8 "\n\t">, #<Nokogiri::XML::Element:0x3fc1014a04dc name="h1" children=[#<Nokogiri::XML::Text:0x3fc1014a02d4 "Example Domain">]>, #<Nokogiri::XML::Text:0x3fc1014a00cc "\n\t">, #<Nokogiri::XML::Element:0x3fc10149fff0 name="p" children=[#<Nokogiri::XML::Text:0x3fc10149fde8 "This domain is established to be used for illustrative examples in documents. You do not need to\n\t\tcoordinate or ask for permission to use this domain in examples, and it is not available for\n\t\tregistration.">]>, #<Nokogiri::XML::Text:0x3fc10149fbe0 "\n\t">, #<Nokogiri::XML::Element:0x3fc10149fb04 name="p" children=[#<Nokogiri::XML::Element:0x3fc10149f8fc name="a" attributes=[#<Nokogiri::XML::Attr:0x3fc10149f898 name="href" value="http://www.iana.org/domains/special">] children=[#<Nokogiri::XML::Text:0x3fc10149f3d4 "More information...">]>]>, #<Nokogiri::XML::Text:0x3fc1014a309c "\n">]>, #<Nokogiri::XML::Text:0x3fc1014a2e94 "\n">]>]>]>
test.rb(main):006:0> page.eof?
=> true
test.rb(main):007:0> page.closed?
=> false
test.rb(main):008:0> page.close
=> nil
test.rb(main):009:0> page.closed?
=> true
test.rb(main):001:0>要求“nokogiri”
=>正确
test.rb(main):002:0>page=File.open('test.html','r')
=> #
test.rb(main):003:0>page.eof?
=>错误
test.rb(main):004:0>page.closed?
=>错误
test.rb(main):005:0>doc=Nokogiri::HTML(第页)
=> #
test.rb(main):006:0>page.eof?
=>正确
test.rb(main):007:0>page.closed?
=>错误
test.rb(main):008:0>page.close
=>零
test.rb(main):009:0>page.closed?
=>正确

因此,换句话说,Nokogiri不会关闭打开的文件

请看我答案的第二部分。太好了。谢谢你也多做了一点。事实上,如果Nokogiri关闭文件,会让人感到惊讶,这些文件是在Nokogiri上下文之外由调用方明确打开的。这也是我的想法,mudasobwa也是如此。这就是问题所在。在我的普通语言中,有一些行之有效的模式来处理这个问题。当我在Ruby中搜索它时,我发现大多数人都说不用担心关闭文件,有些语法我不能完全应用于这个特定的用例。不需要关闭文件和使用语法是一个通用的用例。你的需求将超越这些。我们不知道您的需求是什么,您的代码示例也不足以让我们为您提供不同的建议;很多时候,人们用代码把自己描绘成一个角落——我自己也经常这么做,所以我知道这一点——让其他人看一看,就会发现一条更简单的路径,不需要那些变通方法。并且,仅供参考,选择的答案是关于Nokogiri关闭文件的错误信息。