zip_tricks no recibirá más actualizaciones ni soporte y ya no recibirá mantenimiento. La historia de zip_tricks continúa en zip_kit, que recibirá actualizaciones periódicas y admite todas las funciones de zip_tricks (y más). ¡Gracias por ser parte de la comunidad zip_tricks!
Permite la salida de archivos ZIP en streaming y sin rebobinado desde Ruby.
Inicialmente escrito y como sucesor espiritual de la tirolesa, ahora lo impulsa con orgullo bajo el capó.
Le permite escribir un archivo ZIP en un archivo, socket, cadena o matriz sin tener que rebobinarlo en ningún momento. Se puede utilizar para crear archivos ZIP muy grandes para enviarlos inmediatamente a los clientes o para escribir archivos ZIP grandes sin inflar la memoria.
zip_tricks actualmente maneja todas nuestras necesidades de compresión (millones de archivos ZIP generados por día), por lo que estamos bastante seguros de que es ampliamente compatible con una gran cantidad de aplicaciones de desarchivado de usuario final.
Soporte de sintaxis Ruby 2.1+ (argumentos de palabras clave con valores predeterminados) y un zlib funcional (todo disponible también para jRuby). jRuby puede experimentar problemas al utilizar los métodos de lectura debido a que el argumento de IO#seek
está limitado a tamaños de 32 bits.
La más sencilla es incluir el módulo ZipTricks::RailsStreaming
en su controlador.
class ZipsController < ActionController :: Base
include ZipTricks :: RailsStreaming
def download
zip_tricks_stream do | zip |
zip . write_deflated_file ( 'report1.csv' ) do | sink |
CSV ( sink ) do | csv_write |
csv_write << Person . column_names
Person . all . find_each do | person |
csv_write << person . attributes . values
end
end
end
zip . write_deflated_file ( 'report2.csv' ) do | sink |
...
end
end
end
end
Si desea más comodidades, también puede utilizar zipline, que procesará y transmitirá automáticamente archivos adjuntos (Carrierwave, Shrine, ActiveStorage) y objetos remotos a través de HTTP.
El caso de uso básico es comprimir sobre la marcha. Algunos datos serán almacenados en el búfer del desinflador Zlib, pero el inflado de la memoria será muy limitado. Los datos se escribirán en el destino a intervalos bastante regulares. La compresión desinflada funcionará mejor para cosas como archivos de texto.
out = my_tempfile # can also be a socket
ZipTricks :: Streamer . open ( out ) do | zip |
zip . write_stored_file ( 'mov.mp4.txt' ) do | sink |
File . open ( 'mov.mp4' , 'rb' ) { | source | IO . copy_stream ( source , sink ) }
end
zip . write_deflated_file ( 'long-novel.txt' ) do | sink |
File . open ( 'novel.txt' , 'rb' ) { | source | IO . copy_stream ( source , sink ) }
end
end
Desafortunadamente, con este enfoque es imposible calcular el tamaño del archivo ZIP que se genera, ya que no se sabe qué tan grandes serán los segmentos de datos comprimidos.
Para "extraer" datos de ZipTricks, puede crear un objeto OutputEnumerator
que producirá los fragmentos binarios pieza por pieza y también aplicará cierta cantidad de almacenamiento en búfer. Dado que este OutputEnumerator
responde a #each
y produce cadenas, también puede (¡y debe!) usarse como cuerpo de respuesta de Rack. Devuélvelo a tu servidor web y tendrás tu ZIP transmitido. El bloque que le dé a OutputEnumerator
solo comenzará a ejecutarse una vez que el cuerpo de su respuesta comience a iterarse, cuando realmente envíe la respuesta al cliente (a menos que esté utilizando un servidor web Rack con almacenamiento en búfer, como Webrick).
body = ZipTricks :: Streamer . output_enum do | zip |
zip . write_stored_file ( 'mov.mp4' ) do | sink | # Those MPEG4 files do not compress that well
File . open ( 'mov.mp4' , 'rb' ) { | source | IO . copy_stream ( source , sink ) }
end
zip . write_deflated_file ( 'long-novel.txt' ) do | sink |
File . open ( 'novel.txt' , 'rb' ) { | source | IO . copy_stream ( source , sink ) }
end
end
[ 200 , { } , body ]
Utilice SizeEstimator
para calcular el tamaño correcto del archivo resultante.
# Precompute the Content-Length ahead of time
bytesize = ZipTricks :: SizeEstimator . estimate do | z |
z . add_stored_entry ( filename : 'myfile1.bin' , size : 9090821 )
z . add_stored_entry ( filename : 'myfile2.bin' , size : 458678 )
end
# Prepare the response body. The block will only be called when the response starts to be written.
zip_body = ZipTricks :: RackBody . new do | zip |
zip . add_stored_entry ( filename : "myfile1.bin" , size : 9090821 , crc32 : 12485 )
zip << read_file ( 'myfile1.bin' )
zip . add_stored_entry ( filename : "myfile2.bin" , size : 458678 , crc32 : 89568 )
zip << read_file ( 'myfile2.bin' )
end
[ 200 , { 'Content-Length' => bytesize . to_s } , zip_body ]
No es necesario que "alimente" todo el contenido de los archivos que guardó en el archivo a través del objeto Streamer. Si el destino de escritura para su caso de uso es un Socket
(digamos, está escribiendo usando Rack hijack) y conoce los metadatos del archivo de antemano (el CRC32 del archivo sin comprimir y los tamaños), puede escribir directamente en ese socket usando alguna técnica de escritura acelerada y solo use Streamer para escribir los metadatos ZIP.
# io has to be an object that supports #<<
ZipTricks :: Streamer . open ( io ) do | zip |
# raw_file is written "as is" (STORED mode).
# Write the local file header first..
zip . add_stored_entry ( filename : "first-file.bin" , size : raw_file . size , crc32 : raw_file_crc32 )
# Adjust the ZIP offsets within the Streamer
zip . simulate_write ( my_temp_file . size )
# ...and then send the actual file contents bypassing the Streamer interface
io . sendfile ( my_temp_file )
end
Consulte el directorio examples/
en la raíz del proyecto. Esto le dará una buena idea de los diversos casos de uso que admite la biblioteca.
BlockCRC32
calcula la suma de comprobación CRC32 de un IO en forma de transmisión. Es un poco más conveniente para este propósito que usar las funciones sin formato de la biblioteca Zlib.
crc = ZipTricks :: StreamCRC32 . new
crc << next_chunk_of_data
...
crc . to_i # Returns the actual CRC32 value computed so far
...
# Append a known CRC32 value that has been computed previosuly
crc . append ( precomputed_crc32 , size_of_the_blob_computed_from )
También puede calcular el CRC32 para un objeto IO completo si responde a #eof?
:
crc = ZipTricks :: StreamCRC32 . from_io ( file ) # Returns an Integer
La biblioteca contiene un módulo de lectura, juegue con él para ver qué es posible. No es un lector ZIP completo, pero fue diseñado para un propósito específico (desempaquetado altamente paralelo de archivos ZIP almacenados remotamente) y, como tal, realiza su función bastante bien. Tenga cuidado con las implicaciones de seguridad del uso de lectores ZIP que no han sido verificados formalmente (el nuestro no lo ha sido).
main
para asegurarse de que la función no se haya implementado o que el error aún no se haya solucionado.Copyright (c) 2020 WeTransfer.
zip_tricks
se distribuye bajo las condiciones de la Licencia Hipocrática. Consulte LICENSE.txt para obtener más detalles. Si esta licencia no es aceptable para su caso de uso, aún mantenemos el árbol de versiones 4.x que permanece bajo la licencia MIT; consulte https://rubygems.org/gems/zip_tricks/versions para obtener más información. Tenga en cuenta que solo respaldamos algunas optimizaciones de rendimiento y correcciones de errores cruciales, pero no las nuevas características de ese árbol.