2013-03-01 37 views
2

在Ruby中,當對開放文件的引用傳遞給另一個對象時,如下面的代碼所示,是否需要將其他對象引用包裝在「begin/ensure」塊中,以確保非託管資源被關閉,還是有另一種方式?Ruby:確保文件在由不同對象持有引用時關閉?

感謝

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

回答

6

在一般情況下,這是確定不用擔心留下打開一個文件,如果不出意外將在試圖寫它,你的程序是不是長期運行的應用程序。當Ruby關閉並退出時,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\[email protected] (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 

所以,換句話說,引入nokogiri不關閉打開的文件。

+0

完美。謝謝你也多花一點時間。 – user2029783 2013-03-01 03:10:10

+0

事實上,Nokogiri會關閉文件,在Nokogiri環境之外被調用者明確打開,這將是令人驚訝的。 – mudasobwa 2013-03-01 06:16:30

+0

這是我的想法以及mudasobwa。因此,這個問題。在我的正常語言中,有很好的模式來處理這個問題。當我在Ruby中搜索它的時候,我發現大多數人說不用擔心關閉這些文件,有些語法我不太適用於這個特殊的用例。 – user2029783 2013-03-01 12:06:15

1

我相信,引入nokogiri會盡快,因爲它是閱讀關閉文件,但如何是安全的,並與File.read

更新

都能跟得上更換File.open,如錫文指出,nokogiri在閱讀完後並沒有關閉文件句柄。對付它的正確方法仍然是:

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

查看我答案的第二部分。 – 2013-03-01 02:49:02

相關問題