2011-10-21 12 views
5

基本的には、メモリからtar/gz形式(おそらく複数のファイルがタールにストリームされますが、HARDDRIVEには触れないでストリーミングするだけです)にデータをストリームしたい場合は、私の場合はHTTPリクエスト本体)。ruby​​ streaming tar/gz

これを行うことができる既存のライブラリを知っている人はいますか? Railsに何かありますか?

libarchive-rubyはCラッパーにすぎず、非常にプラットフォームに依存するようです(ドキュメントはインストール手順としてコンパイルしてほしいですか?)。

SOLUTION:

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 

それです! GzipWriterのファイルをIOでスワップして、ストリーミングを維持することができます。 dw11wtqのクッキー!

+0

これは実際にはメモリが集中していることを指摘する必要があります。これはgzipストリームに行く前にStringIOをtarでいっぱいにします。大きなファイルのより良い解決策は、ストリーム間にバッファを作成することです。これを実現するためにコードを追加します... –

+1

gz.closeも出力IO(この場合File)を閉じることに注意してください。開いたままにするには、gz.finishを使用してください。 –

答えて

6

ruby​​gemsのTarWriterクラスを見てみましょう。http://rubygems.rubyforge.org/rubygems-update/Gem/Package/TarWriter.htmlこれはIOストリーム(StringIOでもよい)で動作します。

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 

また、tarballにディレクトリレイアウトが必要な場合は、ディレクトリを追加する方法も提供されています。参考のため

、あなたは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ストリームから出力BOTHを読むことはできますか?私はハードディスクに触れたくないので、ファイルは許可されていません! –

+0

また、プラットフォームごとに独立している必要があります。私はむしろシステムコールに依存しません。私が使用するツールは、gemやrbファイルのように自分でパッケージ化できるライブラリである必要があります。これが私がlibarchive-rubyから離れた理由です。 –

+0

もう一度見て、これは動作する可能性があります。私はzlib :: zlib :: GzipWriterは入力と出力の両方にストリームを使用でき、TarWriterはStringIOを使うこともできると思います。私はそれを試し、それが動作すればあなたにクッキーを与えるでしょう。 –

0

OPが書いた解決策に基づいて、私は完全にメモリ上のtgzアーカイブ機能を書いて、WebサーバーへのPOSTに使用したいものを書きました。

# 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