読者です 読者をやめる 読者になる 読者になる

カッパでも分かるiOSアプリゲーム開発

カッパがひたすらゲーム制作に関することを書くブログです。Railsに関するTipsもたまにまとめてます。

rubyzip でzipファイルを展開し、それぞれファイル処理していく

Rails
スポンサードリンク

Ruby on Rails 4 アプリケーションプログラミング
f:id:InvokeTwoA:20151023183618p:plain「最近は Rails の記事ばかりあげてるなー」
f:id:InvokeTwoA:20151215172640p:plain「2月は仕事とか某穴埋め問題が忙しいですからねー」
f:id:InvokeTwoA:20151023183618p:plain「かっぱクエストも技術的な目標はクリアしたけど、肝心の戦闘シーンが思いつかないので止まり中という」
f:id:InvokeTwoA:20151215172640p:plain(初めに考えてから開発すれば良いのに)
【目次】

やりたいこと

f:id:InvokeTwoA:20151108161835j:plain

  • zip ファイルをアップロードし、展開されたファイルをそれぞれ処理する
  • Rails でやりたい

まず rubyzip をインストールする

gem 'rubyzip', '>= 1.0.0'

f:id:InvokeTwoA:20151023183618p:plain「そして bundle install して rails を再起動……」
f:id:InvokeTwoA:20151215172640p:plain「当たり前のことだけど再起動をたまに忘れちゃうんですよねー」

html で入力フォームを作る

  - form_for Höge.new , html: { multipart: true } do |f|
    = file_field_tag :upload_file
  • 上記の例は haml 用いて作成
  • ファイルアップロードできれば何でも良い

controller でアップロードされたファイルを展開する

  • 今回の例では params[:upload_file] にアップロードされたファイルの内容が来る
  • 今回は import コントローラーで処理をする
  def import
    require 'zip'
    upload_file = params[:pdf_file]
    Zip::File.open(upload_file.path) do |zip|
      zip.each do |archive|
        tmp_file_path = "tmp/#{File.basename(archive.to_s)  }"
        archive.extract(tmp_file_path) { true }

        # 後は tmp_file_path を好きに File.open するなり carrierwave で保存するなりすれば良い
      end
    end
  end

f:id:InvokeTwoA:20151023183618p:plain「ここでちょっと質問をば」
f:id:InvokeTwoA:20151215172640p:plain「なんですか、かっぱ君」
f:id:InvokeTwoA:20151023183618p:plain「extract って何をやってるんですか?」

  • archive には展開された各ファイルが入る(ただし # の形。これが非常に扱いづらい)
  • archive.extract(filepath) で filepath に展開したファイルを保存する(既にファイルが存在してたらエラーになる)
  • archive.extract(filepath) {true} で、もし filepath に既にファイルが保存していたら上書きをする

f:id:InvokeTwoA:20151023183618p:plain「Zip::Entry の形だと非常に扱いずらいけど、一度ファイルに書き込んでしまえば後は carrierwave とかで簡単に処理ができるね」
f:id:InvokeTwoA:20151215172640p:plain「もっと良い方法があっても良さそうなんですけどねー」

※ ちなみに rubyzip は昔のバージョンだと Zip::File ではなく Zip::ZipFile になってるので注意
※ archive.get_input_stream で Zip::InputStream の形式でデータを扱う事ができる
※ archive.get_input_stream.read でファイルを読み込む事もできる
※ archive.directory? で展開したものがディレクトリかどうかなども判定できる

総括

f:id:InvokeTwoA:20151023183618p:plain「あまりに基本すぎる事だったけど、なんか日本語記事があんまし良いのがなかったので書いてみたよ」
f:id:InvokeTwoA:20151215172640p:plain「偉い!」