Techioz Blog

Rubyでパスワード保護された(オプションとして)zipファイルを生成するにはどうすればよいですか?

概要

基本的なアーカイブの作成は次のように行われます (rubyzip を使用)

Zip::File.open(zipfile_name, create: true) do |zipfile|
  input_filenames.each do |filename|
    zipfile.add(filename, File.join(folder, filename))
  end
end

さて、しばらく前にうまくいくようになりました…しかし、今度はパスワードで保護された zip を作成する必要があります。このために、ドキュメントには次のものが含まれています。

enc = Zip::TraditionalEncrypter.new('password')
buffer = Zip::OutputStream.write_buffer(encrypter: enc) do |output|
  output.put_next_entry("my_file.txt")
  output.write my_data
end

最初のアプローチ(ファイルのリストを反復処理する)と組み合わせる方法がよくわかりません。

また、私の場合、パスワードはオプションです。アーカイブをパスワードで保護するかどうかはユーザーの選択です。それぞれの場合にまったく異なるコードを使用する必要があるのは避けたいと考えています。

解決策

ご覧のとおり、デフォルトでは暗号化機能は nil です

ただし、必要に応じて動的に渡すことができます

私はそのような方法を提案します:

require "zip"

def zipfile(filenames:, zip_filename:, password: nil)
  # If password was passed, intitialize encrypter
  encrypter = Zip::TraditionalEncrypter.new(password) if password

  # Create buffer, it is the object like StringIO
  # Pass encrypter there, it will be nil if no password
  buffer = Zip::OutputStream.write_buffer(encrypter: encrypter) do |out|
    Array(filenames).each do |filename|
      # Create file inside zip archive
      out.put_next_entry(File.basename(filename))
      # And fill with file content
      out.write File.read(filename)
    end
  end

  # Write result to the zip file
  File.open(zip_filename, "w") { |zipfile| zipfile.write(buffer.string) }
end

もちろん、必要に応じて変更したり、別のエンティティを作成したりできます

これで、パスワードを渡す/渡さないで、文字列またはファイル名の配列を渡してこのメソッドを呼び出すことができます。

zipfile(filenames: ["1.txt", "2.txt"], zip_filename: "new.zip", password: "123456")
zipfile(filenames: "/Users/abc/111.txt", zip_filename: "/Users/abc/111.zip")

ご覧のとおり、これはrubyzip 3.0のかなり新しい機能であり、このバージョンを(たとえばGemfileで)指定する必要があります。

# Gemfile
source "https://rubygems.org"

gem "rubyzip", "3.0.0.alpha"

そして、そのバージョンのコンテキストでスクリプトを実行するとします。

bundle exec ruby zipper.rb