2010-03-09 23 views
32

He generado muchos archivos PDF en la memoria y quiero comprimirlos en un archivo zip antes de enviarlo como un archivo adjunto de correo electrónico. Miré a Rubyzip y no me permite crear un archivo zip sin guardarlo en el disco (tal vez estoy equivocado).¿Cómo puedo generar un archivo zip sin guardarlo en el disco con Ruby?

¿Hay alguna manera de comprimir esos archivos sin crear un archivo temporal?

+0

Ver [la respuesta de @vas] (http://stackoverflow.com/a/9712252/244128), ¡hace exactamente lo que quieres! – maerics

Respuesta

38

Tuve un problema similar que resolví utilizando la gema rubyzip y el objeto stringio. Resulta que rubyzip proporciona un método que devuelve un objeto de cadena: ZipOutputStream.write_buffer.

Puede crear la estructura de archivos zip como desee usando put_next_entry y escribir, y una vez que haya terminado puede rebobinar la cadena y leer los datos binarios usando sysread.

Vea el siguiente ejemplo simple (funciona para 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 

probado en jruby 1.6.5.1 (rubí-1.9.2-p136) (2011-12-27 1bf37c2) (Java HotSpot (TM) de 64 bits del servidor VM 1.6.0_29) [Windows Server 2008 amd64 java])

el siguiente ejemplo se trabaja para 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 

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

+0

Gracias, funciona. Sin embargo, en el momento en que escribí la pregunta, el método aún no existía. Fue agregado en 2011-01-07. Gracias por su respuesta y la próxima vez que necesite comprimir en la memoria, sabré cómo hacerlo. – Martinos

+1

LoadError no puede cargar dicho archivo - zip –

+1

Arriba funciona con versiones anteriores de rubyzip gem. La versión 1.0 cambió la interfaz. Por favor, consulte: https://github.com/rubyzip/rubyzip#important-note – vas

1

Hay dos bibliotecas RubyZip que pude encontrar.

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

la biblioteca de Chilkat definitivamente Permite crear un archivo zip en la memoria en lugar de escribir en el disco de forma automática como se ve en estos enlaces: Zip to Memory, Zip from in memory data

El uno en SourceForge, por otro lado, puede proporcionar una opción de comprimir un archivo en la memoria, pero no estoy del todo seguro, ya que soy muy nuevo en ruby. El rubyzip de SourceForge se basa en java.util.zip, lo que lo llevó a tener una clase llamada ZipOutputStream. No sé lo bien que la aplicación es rubyzip, pero con la aplicación java.util.zipOutputStream se puede configurar para ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream ....

Si eso es cierto para la implementación rubyzip entonces debería ser una cuestión de usar ZipOutputStream para pasar un tipo de ByteArrayOutputStream que daría como resultado que salga a la memoria.

Si no existe en rubyzip, entonces estoy seguro de que siempre puedes escribir tu propia implementación y enviarla para su inclusión en rubyzip, ya que es de código abierto.

+0

El que me refería era la gema: http://rubygems.org/gems/rubyzip No quiero usar la biblioteca Chilkat ya que allí no es de código abierto. – Martinos

+0

No rebajaré esto, pero no encontré en ningún lado un comentario como "no, las clases estándar de Ruby ZIP NO pueden hacer esto". Creo que deberías haber comenzado con eso. – dimitarvp

+0

De hecho, el nuevo método ZipOutputStream toma un nombre de archivo como argumento, no encontré ninguna forma de pasar un objeto IO. – Martinos

0

Si está en Linux, y dependiendo de la cantidad de RAM que tenga, y qué tan grandes sean sus archivos, siempre puede usar tmpfs (memoria compartida). Entonces, los métodos basados ​​en discos rubyzip funcionarán. http://www.mjmwired.net/kernel/Documentation/filesystems/tmpfs.txt

+0

El montaje requiere permisos de superusuario –

+0

@AbeVoelker sí, esta respuesta supone que usted ya tiene un tmpfs, o tiene un administrador de sistema local amigable. – g33kz0r

5

Ruby viene con una muy conveniente biblioteca StringIO - esto se puede utilizar para usar un String como objeto IO de salida o simular la lectura de un archivo respaldado por un String.

El reto aquí es que RubyZip no soporta tomar directamente un objeto IO al crear un Zip::ZipOutputStream, pero si nos fijamos en la aplicación de la initialize, y dependiendo de su disposición a experimentar, es posible que pueda extender la clase y permita que tome un objeto IO o un nombre de archivo en el constructor.

Cuestiones relacionadas