2011-09-19 7 views
12

일부 데이터를 XML 파일에 쓰고 싶습니다. (XML 파일은 ~ 50MB가됩니다).루비에 큰 파일 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 

노코 기리 약 143초 걸리고 또한 메모리 소비가 점차 증가하고 약 700 메가 바이트 마침내 끝났다.

빌더는 약 123 초가 걸리고 메모리 소비는 10MB 정도로 안정적이었습니다.

Ruby에서 거대한 XML 파일 (50MB)을 작성하는 더 좋은 해결책이 있습니까?

노코 기리 파일 :

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

다시 구문 분석 : (뿐만 아니라 nogokiri에서 사용 가능) 노코 기리 매우 사용자 친화적 인, 그러나 속도가 중요한 때, 난 그냥 SAX 파서를 작성하기위한 이동 . 나는 내가 blazingly 빨리 XML에서 필요한 물건의 배열을 구축하는 데 사용하는 편리한 유틸리티 클래스가 (XML은 매우 간단합니다 제공) https://gist.github.com/854726 그렇지 않으면 내가해야 할 수도 있습니다 사용자 정의 saxparser를 작성하십시오. – sunkencity

+0

당신은 그것을 다른 방법으로 가져 왔습니다. 배열 (활성 레코드)에서 XML을 만들고 싶습니다. –

+0

"구문 분석에 가장 효율적인 것으로 nokogiri (1.5.0) gem을 찾았습니다."에 대한 의견이었습니다. 요점은 구문 분석에 가장 효율적인 방법은 saxparser API를 직접 사용하는 것입니다. – sunkencity

답변

15

솔루션 1

, 난 그냥 (http://libxml.rubyforge.org/rdoc/)를 libxml - 루비를 사용하십시오 직접 :

$ 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) 

입니다 : 들여 쓰기 =>이 경우 큰 차이를하지 않는 사실 만이 할 수있는 더 복잡한 XML 파일.

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

가장 빠른 솔루션 물론 해결책이

, 그 메모리에 구축하지 않습니다 (들여 쓰기)

$ 시간 루비 test.rb 번호 단지를 작성하는 것입니다 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

, 왜 빌더 자체를 사용하지 않습니까? , 그것은 검증을 제공하고 또한 더 안전 할 것입니다, 그렇죠? –