2011-09-19 47 views
12

我想將一些數據寫入XML文件(XML文件將達到〜50 MB)。在ruby中創建大文件xml

我發現nokogiri(1.5.0)寶石是最有效的解析(只讀和不寫)。 Nokogiri不是寫入XML文件的好選擇,因爲它將完整的XML數據保存在內存中,直到寫入最終寫入爲止。

我發現建設者(3.0.0)是一個很好的選擇,但不知道如果它是最好的選擇。

我嘗試了一些基準測試下面的簡單代碼:

(1..500000).each do |k| 
    xml.products { 
     xml.widget { 
     xml.id_ k 
     xml.name "Awesome widget" 
     } 
    } 
    end 

引入nokogiri花費約143ng秒,也內存消耗逐漸增加,最終終於在大約700 MB。

Builder需要大約123秒,內存消耗在10 MB時足夠穩定。

那麼是否有更好的解決方案在Ruby中編寫巨大的XML文件(50 MB)?

引入nokogiri文件:

require 'rubygems' 
require 'nokogiri' 
a = Time.now 
builder = Nokogiri::XML::Builder.new do |xml| 
    xml.root { 
    (1..500000).each do |k| 
    xml.products { 
     xml.widget { 
     xml.id_ k 
     xml.name "Awesome widget" 
     } 
    } 
    end 
    } 
end 
o = File.new("test_noko.xml", "w") 
o.write(builder.to_xml) 
o.close 
puts (Time.now-a).to_s 

生成文件:

require 'rubygems' 
require 'builder' 
a = Time.now 
File.open("test.xml", 'w') {|f| 
xml = Builder::XmlMarkup.new(:target => f, :indent => 1) 

    (1..500000).each do |k| 
    xml.products { 
     xml.widget { 
     xml.id_ k 
     xml.name "Awesome widget" 
     } 
    } 
    end 

} 
puts (Time.now-a).to_s 
+0

重新解析:引入nokogiri是相當人性化,但是當速度是關鍵,我去只是寫一個SAX解析器(在nogokiri可爲好) 。我有一個方便的工具類,我用它來快速地構建我需要從xml中獲得的東西的數組(假設xml非常簡單)https://gist.github.com/854726 if else else寫一個自定義的saxparser。 – sunkencity

+0

你採取了其他方式..我想從數組(積極的記錄)構建XML。 –

+0

這是對「我發現nokogiri(1.5.0)gem是最有效解析的評論」,我的觀點是解析最有效的方法是直接使用saxparser api。 – sunkencity

回答

15

解決方案1 ​​

如果速度是你的主要關注,我只是使用的libxml-紅寶石(http://libxml.rubyforge.org/rdoc/)直接:

$ time ruby test.rb 

real 0m7.352s 
user 0m5.867s 
sys  0m0.921s 

的API是非常直截了當

require 'rubygems' 
require 'xml' 
doc = XML::Document.new() 
doc.root = XML::Node.new('root_node') 
root = doc.root 

500000.times do |k| 
    root << elem1 = XML::Node.new('products') 
    elem1 << elem2 = XML::Node.new('widget') 
    elem2['id'] = k.to_s 
    elem2['name'] = 'Awesome widget' 
end 

doc.save('foo.xml', :indent => false, :encoding => XML::Encoding::UTF_8) 

使用:縮進=> true在這種情況下,沒有做太大的區別,但對於更復雜的XML文件,它可能會做。

$時間紅寶石test.rb#(與縮進)

real 0m7.395s 
user 0m6.050s 
sys  0m0.847s 

解決方案2

當然最快的解決方案,並且不堆積在內存只是寫xml手動,但很容易產生其他錯誤的來源,如可能無效的XML。

$ time ruby test.rb 

real 0m1.131s 
user 0m0.873s 
sys  0m0.126s 

這裏是該代碼:

f = File.open("foo.xml", "w") 
f.puts('<doc>') 
500000.times do |k| 
    f.puts "<product><widget id=\"#{k}\" name=\"Awesome widget\" /></product>" 
end 
f.puts('</doc>') 
f.close 
+0

但與此內存高達600 MB ..這太錯了不是嗎? –

+0

我添加了一種方法來做到這一點,但沒有耗盡內存,速度更快,但是您沒有獲得使用xml生成器的好處,如自動縮進,檢查有效性等。 – sunkencity

+0

解決方案2的情況下,爲什麼不使用生成器本身?它會提供驗證並且更安全,不是嗎? –