当引用由不同对象持有时,如何确保关闭文件



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

@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>"]

一般来说,如果没有其他文件试图写入,并且您的程序不是一个长时间运行的应用程序,那么不用担心打开单个文件是可以的。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 "ntbody {nttbackground-color: #f0f0f2;nttmargin: 0;nttpadding: 0;nttfont-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;nnt}ntdiv {nttwidth: 600px;nttmargin: 5em auto;nttpadding: 3em;nttbackground-color: #fff;nttborder-radius: 1em;nt}nta:link, a:visited {nttcolor: #38488f;ntttext-decoration: none;nt}nt@media (max-width: 600px) {nttbody {ntttbackground-color: #fff;ntt}nttdiv {ntttwidth: auto;ntttmargin: 0 auto;ntttborder-radius: 0;ntttpadding: 1em;ntt}nt}nt">]>]>, #<Nokogiri::XML::Element:0x3fc1014a0aa4 name="body" children=[#<Nokogiri::XML::Text:0x3fc1014a089c "n">, #<Nokogiri::XML::Element:0x3fc1014a07c0 name="div" children=[#<Nokogiri::XML::Text:0x3fc1014a05b8 "nt">, #<Nokogiri::XML::Element:0x3fc1014a04dc name="h1" children=[#<Nokogiri::XML::Text:0x3fc1014a02d4 "Example Domain">]>, #<Nokogiri::XML::Text:0x3fc1014a00cc "nt">, #<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 tonttcoordinate or ask for permission to use this domain in examples, and it is not available fornttregistration.">]>, #<Nokogiri::XML::Text:0x3fc10149fbe0 "nt">, #<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
所以,换句话说,Nokogiri不会关闭打开的文件。

我相信Nokogiri会在读取文件后立即关闭文件,但是如何安全并将File.open替换为File.read


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

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

相关内容

  • 没有找到相关文章

最新更新