1. ayies128

    Posted

    ayies128
Changes in title
+Rails rubyzipでディレクトリを圧縮してダウンロードする
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,132 @@
+# やりたいこと
+こんな感じのディレクトリを含むデータを
+<img width="284" alt="スクリーンショット 2017-10-06 18.12.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/c2a4ba25-dbec-36b0-1370-590f05d581fc.png">
+
+圧縮したい!!
+<img width="185" alt="スクリーンショット 2017-10-06 18.13.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/147005/1fe8ab2b-8998-0902-8cfd-5a9de2b0b213.png">
+
+
+# 使用するgem
+[rubyzip](https://github.com/rubyzip/rubyzip)
+導入はREADMEを読みましょう。
+
+ziprubyってのもあるから間違えないように。
+
+## rubyzipの基本的な使い方
+READMEに書いてある基本的なzip作成方法は以下の通り
+[Basic zip archive creation](https://github.com/rubyzip/rubyzip#basic-zip-archive-creation)
+
+```rb
+require 'rubygems'
+require 'zip'
+
+folder = "Users/me/Desktop/stuff_to_zip"
+input_filenames = ['image.jpg', 'description.txt', 'stats.csv']
+
+zipfile_name = "/Users/me/Desktop/archive.zip"
+
+Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
+ input_filenames.each do |filename|
+ # Two arguments:
+ # - The name of the file as it will appear in the archive
+ # - The original file, including the path to find it
+ zipfile.add(filename, File.join(folder, filename))
+ end
+ zipfile.get_output_stream("myFile") { |os| os.write "myFile contains just this" }
+end
+```
+
+手始めにサンプルを少しいじってローカルにある画像ファイル数個を圧縮してみました。
+簡単にできました。
+その時こう思ったのです。
+「あ、これは勝ちましたね。」と...
+
+そして英語だからってまともにREADMEを読まずに、```zipfile.add```でディレクトリ渡せばできるんじゃ?
+という軽い気持ちで多方面からaddを試してみたんですが、ことごとく敗北。
+負けました。
+
+# 実装
+readmeの少し下を見てみましょう。
+[Zipping a directory recursively](https://github.com/rubyzip/rubyzip#zipping-a-directory-recursively)....ん?流れ変わったな?
+「再帰的にディレクトリを圧縮する」by Google翻訳
+以下ソース
+
+```rb
+require 'zip'
+
+# This is a simple example which uses rubyzip to
+# recursively generate a zip file from the contents of
+# a specified directory. The directory itself is not
+# included in the archive, rather just its contents.
+#
+# Usage:
+# directory_to_zip = "/tmp/input"
+# output_file = "/tmp/out.zip"
+# zf = ZipFileGenerator.new(directory_to_zip, output_file)
+# zf.write()
+class ZipFileGenerator
+ # Initialize with the directory to zip and the location of the output archive.
+ def initialize(input_dir, output_file)
+ @input_dir = input_dir
+ @output_file = output_file
+ end
+
+ # Zip the input directory.
+ def write
+ entries = Dir.entries(@input_dir) - %w(. ..)
+
+ ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |io|
+ write_entries entries, '', io
+ end
+ end
+
+ private
+
+ # A helper method to make the recursion work.
+ def write_entries(entries, path, io)
+ entries.each do |e|
+ zip_file_path = path == '' ? e : File.join(path, e)
+ disk_file_path = File.join(@input_dir, zip_file_path)
+ puts "Deflating #{disk_file_path}"
+
+ if File.directory? disk_file_path
+ recursively_deflate_directory(disk_file_path, io, zip_file_path)
+ else
+ put_into_archive(disk_file_path, io, zip_file_path)
+ end
+ end
+ end
+
+ def recursively_deflate_directory(disk_file_path, io, zip_file_path)
+ io.mkdir zip_file_path
+ subdir = Dir.entries(disk_file_path) - %w(. ..)
+ write_entries subdir, zip_file_path, io
+ end
+
+ def put_into_archive(disk_file_path, io, zip_file_path)
+ io.get_output_stream(zip_file_path) do |f|
+ f.write(File.open(disk_file_path, 'rb').read)
+ end
+ end
+end
+```
+「Copy from here」と書いていますし言われるがままにこのクラスをプロジェクトに配置します。
+すると、素晴らしい。
+インスタンスを作成して```write```メソッドを呼び出すだけで指定したフォルダがzipになるのです。
+
+```rb
+zip_file_generator = ZipFileGenerator.new(input_dir, output_file)
+zip_file_generator.write
+# ディレクトリのzipができる
+```
+
+後はコントローラーで```send_file```を使ってダウンロードさせるだけです。
+
+```rb
+send_file output_file
+
+```
+# 所感
+- READMEはヨンダホウガイイデスヨ
+- なんでgemのライブラリに含んでくれないんですかねえ
+- rubyzipの使い方は結構ググっても出てこない