我在内存中生成了很多PDF文件,我想将它们压缩成一个zip文件,然后再将其作为电子邮件附件发送。我看过Rubyzip并且它不允许我创建一个zip文件而不将其保存到磁盘(也许我错了)。
有没有办法在不创建临时文件的情况下压缩这些文件?
答案 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库。
Chilkat的库绝对允许用户在内存中创建一个zip文件,而不是自动将其写入磁盘,如以下链接所示:Zip to Memory,Zip from in memory data
另一方面,SourceForge上的那个可以提供在内存中压缩文件的选项,但我不完全确定,因为我对ruby很新。 SourceForge rubyzip基于java.util.zip
,导致它有一个名为ZipOutputStream
的类。我不知道rubyzip实现有多好,但通过java.util.zip
实现,OutputStream
可以设置为ByteArrayOutputStream
,FileOutputStream
,FilterOutputStream
,{{ 1}},ObjectOutputStream
,OutputStream
....
如果对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