2011-09-19 6 views
12

में बड़ी फ़ाइल xml बनाना मैं XML फ़ाइल में कुछ डेटा लिखना चाहता हूं (एक्सएमएल फ़ाइल ~ 50 एमबी तक आ जाएगी)।रूबी

मुझे नोकोगिरी (1.5.0) मणि पाया गया है जो सबसे अधिक पार्स करने के लिए कुशल है (बस पढ़ना और लिखना नहीं)। नोकोगिरी एक्सएमएल फाइल को लिखने का एक अच्छा विकल्प नहीं है क्योंकि यह स्मृति में पूरा एक्सएमएल डेटा रखता है जब तक कि यह अंततः लिखता है।

मुझे एक अच्छा विकल्प होने के लिए निर्माता (3.0.0) मिला लेकिन यह सुनिश्चित नहीं है कि यह सबसे अच्छा विकल्प है या नहीं।

मैं निम्नलिखित सरल कोड के साथ कुछ बेंचमार्क की कोशिश की:

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

Nokogiri 143 के बारे में सेकंड लेता है और यह भी स्मृति की खपत धीरे-धीरे वृद्धि हुई है और लगभग 700 एमबी पर अंत में समाप्त हो गया।

बिल्डर ने लगभग 123 सेकंड लिया और मेमोरी खपत 10 एमबी पर पर्याप्त स्थिर थी।

तो रूबी में विशाल एक्सएमएल फाइलें (50 एमबी) लिखने का बेहतर समाधान है?

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 (और साथ nogokiri में उपलब्ध है) बहुत उपयोगकर्ता के अनुकूल है, लेकिन जब गति महत्वपूर्ण है, मैं सिर्फ एक सैक्स पार्सर लिखने के लिए जाना । मेरे पास एक आसान उपयोगिता वर्ग है जिसका उपयोग मैं एक एक्सएमएल से आवश्यक सामानों की एक सरणी को तेजी से बनाने के लिए करता हूं (बशर्ते कि एक्सएमएल बहुत सरल है) https://gist.github.com/854726 अगर मुझे शायद एक कस्टम saxparser लिखें। – sunkencity

+0

आपने इसे अन्य तरीके से लिया .. मैं सरणी (सक्रिय रिकॉर्ड) से एक्सएमएल बनाना चाहता हूं। –

+0

यह एक टिप्पणी थी "मुझे नोकोगिरी (1.5.0) मणि पार्स करने के लिए सबसे कुशल होने के लिए मिला", मेरा पॉइंट पार्स करने का सबसे प्रभावी तरीका है, सीधे सैक्सपार्सर एपीआई का उपयोग करना है। – sunkencity

उत्तर

15

समाधान 1

गति अपने मुख्य चिंता का विषय है, तो मैं बस का उपयोग करेंगे libxml-माणिक (http://libxml.rubyforge.org/rdoc/) सीधे:

$ time ruby test.rb 

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

एपीआई सुंदर सीधे आगे

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 इस मामले में ज्यादा अंतर नहीं करता है, लेकिन और अधिक जटिल एक्सएमएल फ़ाइलें यह कर सकता है के लिए।

$ समय (मांगपत्र के साथ) गहरे लाल रंग का 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 एमबी तक चला जाता है .. यह तरीका बहुत गलत है? –

+0

मैंने स्मृति को खाने के बिना इसे करने का एक तरीका जोड़ा, यह तेज़ है, लेकिन आपको समाधान इंडेक्स जैसे xml जनरेटर का उपयोग करने और वैधता के लिए चेक आदि का कोई लाभ नहीं मिलता है। समाधान 2 के मामले में – sunkencity

+0

, बिल्डर का उपयोग क्यों न करें? , यह सत्यापन प्रदान करेगा और सुरक्षित भी होगा, है ना? –