zip_tricks は今後更新やサポートを受けることはなく、メンテナンスも行われなくなります。 zip_tricks のストーリーは zip_kit に続きます。zip_kit は定期的に更新され、すべての zip_tricks 機能 (およびその他) をサポートします。 zip_tricks コミュニティにご参加いただきありがとうございます。
Ruby からのストリーミング非巻き戻し ZIP ファイル出力を許可します。
当初はジップラインの精神的な後継者として書かれていましたが、現在は内部で誇らしげに機能しています。
いかなる時点でも巻き戻すことなく、ZIP アーカイブをファイル、ソケット、文字列、または配列に書き出すことができます。クライアントに即時に送信するための非常に大きな ZIP アーカイブを作成する場合や、メモリを増やすことなく大きな ZIP アーカイブを書き込む場合に使用できます。
zip_tricks は現在、すべての圧縮ニーズ (1 日に生成される数百万の ZIP ファイル) を処理しているため、多数の解凍エンドユーザー アプリケーションと広く互換性があると確信しています。
Ruby 2.1+ 構文サポート (デフォルトのキーワード引数) および動作する zlib (すべて jRuby でも利用可能)。 IO#seek
の引数が 32 ビット サイズに制限されているため、jRuby ではリーダー メソッドを使用するときに問題が発生する可能性があります。
最も簡単な方法は、 ZipTricks::RailsStreaming
モジュールをコントローラーに組み込むことです。
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
さらに便利にしたい場合は、添付ファイル (Carrierwave、Shrine、ActiveStorage) とリモート オブジェクトを HTTP 経由で自動的に処理およびストリーミングする zipline を使用することもできます。
基本的な使用例は、オンザフライで圧縮します。一部のデータは Zlib デフレーターによってバッファーされますが、メモリーの増加は非常に制限されます。データはかなり一定の間隔で宛先に書き込まれます。 Deflate 圧縮は、テキスト ファイルなどに最適です。
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
残念ながら、このアプローチでは、圧縮されたデータ セグメントがどのくらいの大きさになるかわからないため、出力される ZIP ファイルのサイズを計算することは不可能です。
ZipTricks からデータを「プル」するには、バイナリ チャンクを部分的に生成し、ある程度のバッファリングも適用するOutputEnumerator
オブジェクトを作成できます。このOutputEnumerator
#each
に応答して String を生成するため、Rack 応答本文としても使用できます (そしてそうすべきです!)。それをウェブサーバーに返すと、ZIP がストリーミングされます。 OutputEnumerator
に指定したブロックは、応答本文の反復処理が開始されてから、実際に応答をクライアントに送信するときにのみ実行を開始します (Webrick などのバッファリング Rack Web サーバーを使用している場合を除く)。
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 ]
SizeEstimator
使用して、結果として得られるアーカイブの正しいサイズを計算します。
# 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 ]
Streamer オブジェクトを通じてアーカイブに置いたファイルのすべてのコンテンツを「フィード」する必要はありません。ユースケースの書き込み先がSocket
であり (ラック ハイジャックを使用して書き込みを行っているなど)、事前にファイルのメタデータ (非圧縮ファイルの CRC32 とサイズ) がわかっている場合は、次を使用してそのソケットに直接書き込むことができます。高速書き込み技術を使用し、ZIP メタデータを書き出すために Streamer のみを使用します。
# 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
プロジェクトのルートにあるexamples/
ディレクトリを確認してください。これにより、ライブラリがサポートするさまざまなユースケースについての良いアイデアが得られます。
BlockCRC32
ストリーミング方式で IO の CRC32 チェックサムを計算します。この目的のためには、生の 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 )
#eof?
に応答する場合、IO オブジェクト全体の CRC32 を計算することもできます。 :
crc = ZipTricks :: StreamCRC32 . from_io ( file ) # Returns an Integer
ライブラリにはリーダー モジュールが含まれているので、それを試して何ができるかを確認してください。これは完全な ZIP リーダーではありませんが、特定の目的 (リモートに保存された ZIP ファイルの高度な並列解凍) のために設計されており、その機能を非常にうまく実行します。正式に検証されていない ZIP リーダー (私たちのものは検証されていません) を使用する場合のセキュリティへの影響に注意してください。
main
をチェックして、機能が実装されていないこと、またはバグがまだ修正されていないことを確認してください。著作権 (c) 2020 WeTransfer。
zip_tricks
はヒポクラテス ライセンスの条件に基づいて配布されます。詳細については、LICENSE.txt を参照してください。このライセンスがお客様のユースケースに受け入れられない場合でも、MIT ライセンスの下に残る 4.x バージョン ツリーが維持されます。詳細については、https://rubygems.org/gems/zip_tricks/versions を参照してください。一部のパフォーマンスの最適化と重要なバグ修正のみをバックポートし、新機能はそのツリーにバックポートしないことに注意してください。