如何在不使用Ruby保存到磁盘的情况下生成zip文件?

时间:2010-03-09 00:49:57

标签: ruby zip

我在内存中生成了很多PDF文件,我想将它们压缩成一个zip文件,然后再将其作为电子邮件附件发送。我看过Rubyzip并且它不允许我创建一个zip文件而不将其保存到磁盘(也许我错了)。

有没有办法在不创建临时文件的情况下压缩这些文件?

5 个答案:

答案 0 :(得分:48)

我遇到了类似的问题,我使用rubyzip gem和stringio对象解决了这个问题。 事实证明,rubyzip提供了一个返回stringio对象的方法:ZipOutputStream.write_buffer

您可以使用put_next_entry创建zip文件结构并编写,完成后,您可以回退stringio并使用sysread读取二进制数据。

请参阅以下简单示例(适用于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

在jruby 1.6.5.1(ruby-1.9.2-p136)(2011-12-27 1bf37c2)(Java HotSpot(TM)64位服务器VM 1.6.0_29)上进行测试[Windows Server 2008-amd64-java] )

以下示例适用于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

在OpenJDK 64位服务器VM上测试jruby 1.7.22(1.9.3p551)2015-08-20 c28f492 1.7.0_79-b14 + jit [linux-amd64]和rubyzip gem 1.1.7

答案 1 :(得分:5)

Ruby带有一个非常方便的StringIO库 - 这可用于将String用作输出IO对象或伪造读取由String支持的文件。

这里的挑战是RubyZip在创建Zip::ZipOutputStream时不支持直接获取IO对象,但是如果你看一下initialize的实现,并且根据你的实验意愿,你可以扩展类并允许它在构造函数中获取IO对象或文件名。

答案 2 :(得分:1)

我能找到两个RubyZip库。

  1. Chilkat's Ruby Zip Library
  2. rubyzip on Sourceforge
  3. Chilkat的库绝对允许用户在内存中创建一个zip文件,而不是自动将其写入磁盘,如以下链接所示:Zip to MemoryZip from in memory data

    另一方面,SourceForge上的那个可以提供在内存中压缩文件的选项,但我不完全确定,因为我对ruby很新。 SourceForge ruby​​zip基于java.util.zip,导致它有一个名为ZipOutputStream的类。我不知道rubyzip实现有多好,但通过java.util.zip实现,OutputStream可以设置为ByteArrayOutputStreamFileOutputStreamFilterOutputStream,{{ 1}},ObjectOutputStreamOutputStream ....

    如果对rubyzip实现适用,则应该使用PipedOutputStream传递ZipOutputStream种类,这将导致它被输出到内存。

    如果在rubyzip中不存在,那么我确信你总是可以编写自己的实现并提交它以包含在rubyzip中,因为它是开源的。

答案 3 :(得分:0)

如果您使用的是Linux,并且根据您拥有的RAM量以及文件的大小,您可以始终使用tmpfs(共享内存)。然后,基于rubyzip磁盘的方法将起作用。 http://www.mjmwired.net/kernel/Documentation/filesystems/tmpfs.txt

答案 4 :(得分:0)

可接受的答案效果很好,但并不能解决我的问题。我不想使用write_buffer method,因为它在块关闭后会自动关闭流。下面的代码段使您可以更好地控制流的创建和关闭时间。

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