How can I generate zip file without saving to the disk with Ruby?

后端 未结 5 1326
既然无缘
既然无缘 2020-12-05 06:41

I have generated many PDF files in memory and I want to compress them into one zip file before sending it as a email attachment. I have looked at Rubyzip and it does not all

相关标签:
5条回答
  • 2020-12-05 06:59

    There are two RubyZip libraries that I was able to find.

    1. Chilkat's Ruby Zip Library
    2. rubyzip on Sourceforge

    Chilkat's library definitely allows one to create a zip file in memory instead of writing it to disk automatically as seen in these links: Zip to Memory, Zip from in memory data

    The one on SourceForge, on the other hand, may provide an option of zipping a file in memory but I'm not entirely certain since I'm very new to ruby. The SourceForge rubyzip is based on java.util.zip which has led to it having a class called ZipOutputStream. I don't know how good the rubyzip implementation is, but with java.util.zip implementation the OutputStream can be set to ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream....

    If that holds true for the rubyzip implementation then it should be a matter of using ZipOutputStream to pass in a ByteArrayOutputStream of sorts which would result in it being output to memory.

    If it doesn't exist in rubyzip, then I'm sure you could always write your own implementation and submit it for inclusion in rubyzip seeing as it is opensource.

    0 讨论(0)
  • 2020-12-05 07:00

    If you're on Linux, and depending upon how much RAM you have, and how large your files are, you could always use tmpfs (shared memory). Then, the rubyzip disk-based methods will work. http://www.mjmwired.net/kernel/Documentation/filesystems/tmpfs.txt

    0 讨论(0)
  • 2020-12-05 07:01

    I had a similar problem which I solved using the rubyzip gem and the stringio object. It turns out that rubyzip provides a method that returns a stringio object: ZipOutputStream.write_buffer.

    You can create the zip file structure as you like using put_next_entry and write and once you are finished you can rewind the stringio and read the binary data using sysread.

    See the following simple example (works for rubyzip 0.9.X)

    require 'zip/zip'
    stringio = Zip::OutputStream.write_buffer do |zio|
      zio.put_next_entry("test.txt")
      zio.write "Hello world!"
    end
    stringio.rewind
    binary_data = stringio.sysread
    

    Tested on jruby 1.6.5.1 (ruby-1.9.2-p136) (2011-12-27 1bf37c2) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [Windows Server 2008-amd64-java])

    The following example works for rubyzip >= 1.0.0

    require 'rubygems'    
    require 'zip'
    stringio = Zip::OutputStream.write_buffer do |zio|
      zio.put_next_entry("test.txt")
      zio.write "Hello world!"
    end
    binary_data = stringio.string
    

    Tested on jruby 1.7.22 (1.9.3p551) 2015-08-20 c28f492 on OpenJDK 64-Bit Server VM 1.7.0_79-b14 +jit [linux-amd64] and rubyzip gem 1.1.7

    0 讨论(0)
  • 2020-12-05 07:14

    The accepted answer works well but it didn't solve my problem. I didn't want to use the write_buffer method because it automatically closes the stream after the block closes. The code snippet below gives you more control over when the stream is created and closed.

    require 'stringio'
    require 'zip'
    
    io = StringIO.new
    zip_io = Zip::OutputStream.new(io, true) # 'true' indicates 'io' is a stream
    zip_io.put_next_entry('test.txt')
    zip_io.write('Hello world!')
    
    # Read the data and close the streams
    io.rewind
    binary_data = io.read
    zip_io.close_buffer
    io.close
    
    0 讨论(0)
  • 2020-12-05 07:21

    Ruby comes with a very convenient StringIO library - this can be used for using a String as output IO object or faking reading a file backed by a String.

    The challenge here is that RubyZip does not support directly taking an IO object when creating a Zip::ZipOutputStream, but if you look at the implementation of the initialize, and depending on your willingness to experiment, you may be able to extend the class and allow it to take either an IO object or a file name in the constructor.

    0 讨论(0)
提交回复
热议问题