2011-10-21 10 views
5

असल में मैं मेमोरी से डेटा को एक टैर/जीजे प्रारूप (संभवतः टैर में कई फाइलों में स्ट्रीम करना चाहता हूं, लेकिन इसे कभी भी हार्डड्राइव नहीं करना चाहिए, केवल स्ट्रीमिंग करना चाहिए!), फिर उन्हें कहीं और स्ट्रीम करें (एक मेरे मामले में HTTP अनुरोध निकाय)।रूबी स्ट्रीमिंग tar/gz

कोई भी मौजूदा पुस्तकालय के बारे में जानता है जो यह कर सकता है? क्या रेल में कुछ है?

libarchive-ruby केवल एक सी रैपर है और ऐसा लगता है कि यह बहुत मंच-निर्भर होगा (दस्तावेज़ चाहते हैं कि आप एक इंस्टॉलेशन चरण के रूप में संकलित करें ?!)।

समाधान:

require 'zlib' 
require 'rubygems/package' 

tar = StringIO.new 

Gem::Package::TarWriter.new(tar) { |writer| 
    writer.add_file("a_file.txt", 0644) { |f| 
    (1..1000).each { |i| 
     f.write("some text\n") 
    } 
    } 
    writer.add_file("another_file.txt", 0644) { |f| 
    f.write("some more text\n") 
    } 
} 
tar.seek(0) 

gz = Zlib::GzipWriter.new(File.new('this_is_a_tar_gz.tar.gz', 'wb')) # Make sure you use 'wb' for binary write! 
gz.write(tar.read) 
tar.close 
gz.close 

यह है कि! स्ट्रीमिंग को रखने के लिए आप किसी भी IO के साथ GzipWriter में फ़ाइल को स्वैप कर सकते हैं। Dw11wtq के लिए कुकीज़!

+0

मुझे यह भी इंगित करना चाहिए कि यह वास्तव में स्मृति गहन है - यह gzip स्ट्रीम पर जाने से पहले स्ट्रिंगियो को पूरे टैर से भर देगा। बड़ी फ़ाइलों के लिए एक बेहतर समाधान धाराओं के बीच एक बफर बनाना होगा। जब मैं इसे कार्यान्वित करने के लिए चारों ओर जाता हूं तो मैं इसके लिए कोड जोड़ूंगा ... –

+1

यह भी ध्यान दें कि gz.close आउटपुट IO (इस मामले में फ़ाइल) को भी बंद कर देगा। इसे खोलने के लिए, gz.finish –

उत्तर

6

rubygems में TarWriter कक्षा पर एक नज़र डालें: http://rubygems.rubyforge.org/rubygems-update/Gem/Package/TarWriter.html यह सिर्फ एक आईओ स्ट्रीम पर काम करता है, जो एक स्ट्रिंगियो हो सकता है।

tar = StringIO.new 

Gem::Package::TarWriter.new(tar) do |writer| 
    writer.add_file("hello_world.txt", 0644) { |f| f.write("Hello world!\n") } 
end 

tar.seek(0) 

p tar.read #=> mostly padding, but a tar nonetheless 

यदि आपको टैरबॉल में निर्देशिका लेआउट की आवश्यकता है तो यह निर्देशिका जोड़ने के तरीकों को भी प्रदान करता है।

संदर्भ के लिए, आप प्राप्त कर सकते थे IO.popen साथ gzipping, बस में डेटा पाइप/प्रणाली प्रक्रिया से बाहर:

gzippped_data = IO.popen("gzip", "w+") do |gzip| 
    gzip.puts "Hello world!" 
    gzip.close_write 
    gzip.read 
end 
# => "\u001F\x8B\b\u0000\xFD\u001D\xA2N\u0000\u0003\xF3H\xCD\xC9\xC9W(\xCF/\xCAIQ\xE4\u0002\u0000A䩲\r\u0000\u0000\u0000" 
:

http://www.ruby-doc.org/core-1.9.2/IO.html#method-c-popen

ही gzipping कुछ इस तरह दिखेगा

+0

का उपयोग करें क्या यह दोनों tar/gz फ़ंक्शंस में लिखना संभव है और IO स्ट्रीम से आउटपुट दोनों को पढ़ना संभव है? मैं हार्ड डिस्क को छूना नहीं चाहता, इसलिए कोई फाइल अनुमति नहीं है! –

+0

इसके अलावा, इसे प्लेटफॉर्म-इंडिपेंट होना चाहिए, और मैं सिस्टम कॉल पर भरोसा नहीं करता। मेरे द्वारा उपयोग किए जाने वाले टूल पुस्तकालयों की आवश्यकता है, मैं खुद को पैकेज कर सकता हूं, जैसे कि रत्न या आरबी फाइलें। यही कारण है कि मैं libarchive-ruby से दूर भटक गया है। –

+0

फिर से देख रहे हैं, यह काम कर सकता है। मेरा मानना ​​है कि zlib'z Zlib :: GzipWriter इनपुट और आउटपुट दोनों के लिए धाराओं का उपयोग कर सकता है, और जैसा कि आपने उल्लेख किया है, TarWriter स्ट्रिंगियो का भी उपयोग कर सकता है। मैं इसे कोशिश करूंगा और यदि यह काम करता है तो आपको कुकीज़ देगा। –

0

समाधान ओपी द्वारा लिखे गए समाधान के आधार पर, मैंने पूरी तरह से ऑन-मेमोरी tgz संग्रह फ़ंक्शन लिखा है जिसे मैं वेब सर्वर पर पोस्ट करने के लिए उपयोग करना चाहता हूं।

# Create tar gz archive file from files, on the memory. 
    # Parameters: 
    # files: Array of hash with key "filename" and "body" 
    #  Ex: [{"filename": "foo.txt", "body": "This is foo.txt"},...] 
    # 
    # Return:: tar_gz archived image as string 
    def create_tgz_archive_from_files(files) 
    tar = StringIO.new 
    Gem::Package::TarWriter.new(tar){ |tar_writer| 
     files.each{|file| 
     tar_writer.add_file(file['filename'], 0644){|f| 
      f.write(file['body']) 
     } 
     } 
    } 
    tar.rewind 

    gz = StringIO.new('', 'r+b') 
    gz.set_encoding("BINARY") 
    gz_writer = Zlib::GzipWriter.new(gz) 
    gz_writer.write(tar.read) 
    tar.close 
    gz_writer.finish 
    gz.rewind 
    tar_gz_buf = gz.read 
    return tar_gz_buf 
    end 
संबंधित मुद्दे