Ruby流tar / gz

基本上我想将数据从内存流式传输到tar / gz格式(可能是多个文件到tar中,但它永远不应该触及HARDDRIVE,只能流式传输!),然后将它们传输到其他地方(在我的情况下是一个HTTP请求体)。

有人知道现有的库可以做到这一点吗? Rails中有什么东西吗?

libarchive-ruby只是一个C包装器,看起来它非常依赖于平台(文档希望你编译为安装步骤?!)。

解:

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的cookies!

看一下rubygems中的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实现IO.popen ,只需将数据输入/输出系统进程:

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

gzip本身看起来像这样:

 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" 

根据OP写的解决方案,我写了完全内存tgz归档function,我想用什么来POST到Web服务器。

  # 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