2011-10-21 3 views
5

기본적으로 메모리에서 tar/gz 형식으로 데이터를 스트리밍하고 싶습니다 (아마도 여러 파일을 타르에 넣으 려하지 않지만 HARDDRIVE에는 절대 스트리밍하지 않아야합니다!). 그런 다음 다른 곳으로 스트리밍합니다 (HTTP 요청 본문).루비 스트리밍 tar/gz

누구든지이 작업을 수행 할 수있는 기존 라이브러리에 대해 알고 계십니까? 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의 쿠키!

+0

또한 이것은 실제로 메모리를 많이 사용한다는 점을 지적해야합니다. gzip 스트림으로 이동하기 전에 StringIO를 전체 타르로 채 웁니다. 큰 파일에 대한 더 나은 솔루션은 스트림 사이에 버퍼를 만드는 것입니다. 그것을 구현할 때이 코드를 추가 할 것입니다 ... –

+1

gz.close 또한 출력 IO (이 경우 File)를 닫습니다. 열린 상태로 유지하려면 gz.finish를 사용하십시오 –

답변

6

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에 디렉토리 레이아웃이 필요한 경우 디렉토리를 추가하는 방법을 제공합니다.

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

자체를 Gzip으로 압축하는 것은 다음과 같이 보일 것입니다 :

것은 참고로, 당신은 단지에있는 데이터를 배관/시스템 프로세스에서, IO.popen와 Gzip으로 압축 달성 할 수

+0

tar/gz 함수에 쓰고 IO 스트림에서 양쪽 출력을 읽을 수 있습니까? 하드 디스크를 만져보고 싶지 않아 파일을 사용할 수 없습니다! –

+0

또한 플랫폼 독립적이어야하며 시스템 호출에 의존하지 않아야합니다. 필자가 사용하는 도구는 보석 또는 rb 파일과 같이 직접 패키지 할 수있는 라이브러리 여야합니다. 이것이 내가 libarchive-ruby에서 벗어난 이유입니다. –

+0

다시 보니 이것이 효과가있을 수 있습니다. 나는 zlib'z Zlib :: GzipWriter가 입력과 출력 모두에 스트림을 사용할 수 있다고 믿고, TarWriter는 언급 한 것처럼 StringIO를 사용할 수있다. 나는 그것을 시도하고 작동한다면 쿠키를 제공합니다. –

0

OP가 작성한 솔루션을 기반으로 웹 서버에 POST 할 때 사용할 메모리 온 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