2012-12-05 8 views
9

में एक इन-मेमोरी ज़िप फ़ाइल के माध्यम से पुनरावृत्ति कैसे करें मैं एक यूनिट परीक्षण लिख रहा हूं, और उनमें से एक ज़िप फ़ाइल लौटा रहा है और मैं इस ज़िप फ़ाइल की सामग्री को देखना चाहता हूं, इससे कुछ मूल्यों को पकड़ सकता हूं, और मानों को अगले परीक्षणों में पास करें।रूबी

मैं रैक टेस्ट का उपयोग कर रहा हूं, इसलिए मुझे पता है कि मेरी ज़िप फ़ाइल की सामग्री last_response.body के अंदर है। मैंने RubyZip के प्रलेखन को देखा है लेकिन ऐसा लगता है कि यह हमेशा एक फ़ाइल की उम्मीद कर रहा है। चूंकि मैं एक यूनिट टेस्ट चला रहा हूं, इसलिए मैं स्मृति में सबकुछ करना पसंद करता हूं क्योंकि यदि संभव हो तो परीक्षण ज़िप फ़ाइलों के साथ किसी भी फ़ोल्डर को प्रदूषित न करें।

उत्तर

6

नए रूबीज़िप एपीआई का उपयोग करके इस उत्तर के एक अधिक अद्यतित संस्करण के लिए @bronson’s answer देखें।

रूबीज़िप दस्तावेज़ जो आप थोड़े पुराने दिखने के लिए जुड़े हुए हैं। latest release (0.9.9) can handle IO objects, तो आप एक स्ट्रिंगियो (थोड़ा tweaking के साथ) का उपयोग कर सकते हैं।

हालांकि एपीआई एक IO स्वीकार करेंगे, यह अभी भी यह एक फ़ाइल है मान लिया गया लगता है और उस पर path फोन करने की कोशिश करता है, तो पहले बंदर पैच StringIO (यह वास्तव में कुछ भी करने की जरूरत नहीं है) एक path विधि जोड़ने के लिए : की तरह कुछ

require 'stringio' 
class StringIO 
    def path 
    end 
end 

तो फिर तुम कर सकते हैं:

require 'zip/zip' 
Zip::ZipInputStream.open_buffer(StringIO.new(last_response.body)) do |io| 
    while (entry = io.get_next_entry) 
    # deal with your zip contents here, e.g. 
    puts "Contents of #{entry.name}: '#{io.read}'" 
    end 
end 

और सब कुछ स्मृति में किया जाएगा।

1

ज़िप फ़ाइल को अस्थायी फ़ाइल में डंप करने के लिए आप Tempfile का उपयोग कर सकते हैं। Tempfile एक ऑपरेशन-सिस्टम विशिष्ट अस्थायी फ़ाइल बनाता है जिसे आपके प्रोग्राम समाप्त होने के बाद ओएस द्वारा साफ किया जाएगा।

+2

पॉज़िक्स सिस्टम पर, अस्थायी फ़ाइल पहले से ही "हटाई जाती है" जब आप इसे प्राप्त करते हैं, तो कोई क्लीन-अप आवश्यक नहीं है। यह एक निकटतम चीज है जिसे आप एक नग्न फ़ाइलहेडल को एक क्षणिक फ़ाइल ऑब्जेक्ट में प्राप्त कर सकते हैं। – tadman

+0

@tadman नहीं जानता था, धन्यवाद। वह जादू कितना है! – akuhn

13

मैट का जवाब बिल्कुल सही है। यहां इसे नए एपीआई में अपडेट किया गया है:

Zip::InputStream.open(StringIO.new(input)) do |io| 
    while entry = io.get_next_entry 
    if entry.name == 'doc.kml' 
     parse_kml(io.read) 
    else 
     raise "unknown entry in kmz file: #{entry.name}" 
    end 
    end 
end 

और अब स्ट्रिंगियो बंदरपैच की आवश्यकता नहीं है। प्रगति!

0

इस पर बस एक अद्यतन rubyzip में परिवर्तन की वजह से:

Zip::InputStream.open(StringIO.new(zip_file)) do |io| 
    while (entry = io.get_next_entry) 
    # deal with your zip contents here, e.g. 
    puts "Contents of #{entry.name}: '#{io.read}'" 
    end 
end 
3
Zip::File.open_buffer(content) do |zip| 
    zip.each do |entry| 
    decompressed_data += entry.get_input_stream.read 
    end 
end 
+2

कुछ स्पष्टीकरण – MichaelChirico

0

मैट के जवाब से प्रेरित होकर मैं उन 0.9.x rubyzip मणि का उपयोग करना होगा, जो के लिए एक थोड़ा संशोधित समाधान है। मुझे एक नई कक्षा परिभाषा की आवश्यकता नहीं है।

sio = StringIO.new(response.body) 
sio.define_singleton_method(:path) {} #needed to create fake method path TO satisfy the ancient rubyzip 0.9.8 gem 
Zip::ZipInputStream::open_buffer(sio) { |io| 
    while (entry = io.get_next_entry) 
     puts "Contents of #{entry.name}" 
    end 
} 
1

RubyZip संस्करण 1.2.1 के साथ (या शायद कुछ पिछले संस्करणों भी), हम बस Zip::File वर्ग के open_buffer विधि का उपयोग करने की जरूरत है।

RubyZip प्रलेखन से:

#open की तरह, लेकिन एक स्ट्रिंग या खुले आईओ धारा, और एक बफर के आउटपुट डेटा से ज़िप संग्रह सामग्री पढ़ता है। (इसका इस्तेमाल डिस्क पर सहेजने के बिना डाउनलोड किए गए ज़िप संग्रह से डेटा निकालने के लिए किया जा सकता है।)

उदाहरण:

Zip::File.open_buffer(last_response.body) do |zip| 
    zip.each do |entry| 
    puts entry.name 
    # Do whatever you want with the content files. 
    end 
end 
+0

पर कॉपी-पेस्ट-चाल की बजाय समझ को प्रोत्साहित करने के लिए एक लंबा रास्ता तय कर सकता है क्या यह आपके लिए काम कर रहा है? जब मैं ऐसा करता हूं, तो मुझे विस्तृत त्रुटि मिलती है [यहां] (https://github.com/rubyzip/rubyzip/issues/177) – metahamza

0

यह मेरे लिए काम किया। मेरे मामले में मेरे पास केवल एक फ़ाइल है इसलिए मैंने एक निश्चित पथ का उपयोग किया, लेकिन आप अपना रास्ता बनाने के लिए entry.name का उपयोग कर सकते हैं।

input = HTTParty.get(link).body 
Zip::File.open_buffer(input) do |zip_file| 
    zip_file.each do |entry| 
     entry.extract(path) 
    end 
end