[Ruby]ymlファイルに定義されたCSV(TSV)の読み込み処理を行う
こんにちは。Yuraです。 前回に引き続き、Rubyネタです。 今回はRailsは使用しませんので、ご了承ください。
はじめに
Ruby学習の一環として、Rubyのyamlライブラリとcsvライブラリを使い、 ymlファイルに定義されているCSVの一覧から中身を読み取るプログラムを書いてみました。
環境
・OS Windows8.1 64bit ・Ruby 2.2.4p230 ・DB MySQL5.7
実装
読込対象ファイル
まず、ymlファイルに読み込みたいファイル名を記述します。 私はこんな感じで作りました。
csv_folder: ./csv/ #CSV置場のディレクトリ csv_files: - test.csv #読み込みたいcsv名 - test.tsv #読み込みたいtsv名
CSVファイルは、テスト用にサンプル売上データを作りました。 今回はcsvファイルだけでなく、tsvファイルも読み込んでみるので、 tsvファイルも用意します。
sales_no,shop_cd,customer_cd,amount,sales_date SAL0000001,SHOP001,CUST001,120000,2016/03/01 SAL0000002,SHOP001,CUST001,230000,2016/03/02 SAL0000003,SHOP001,CUST002,340000,2016/03/02 SAL0000004,SHOP001,CUST002,450000,2016/03/02 SAL0000005,SHOP002,CUST030,560000,2016/03/04
sales_no shop_cd customer_cd amount sales_date SAL0000006 SHOP003 CUST100 980000 2016/03/01 SAL0000007 SHOP003 CUST100 760000 2016/03/02 SAL0000008 SHOP003 CUST100 540000 2016/03/02 SAL0000009 SHOP003 CUST100 320000 2016/03/02 SAL0000010 SHOP003 CUST100 100000 2016/03/04
ソースコード
実装したRubyのソースは以下の通りです。 Readerクラスを作成しました。 get_pathsメソッドでymlファイルから読込対象のCSVのパスを取得し、 readメソッドでCSVの中身を読み出します。 tsvファイルも、区切り文字にタブを指定することによって、CSVと同じように扱えます。
class Reader # ymlファイルに定義されたCSVのパスを取得 def self.get_paths yaml = YAML.load_file("csvList.yml") csv_folder = yaml["csv_folder"] csv_files = yaml["csv_files"] csv_paths = Array.new csv_files.each do |file| csv_path = File.expand_path(csv_folder + file) csv_paths.push(csv_path) end return csv_paths end # CSV(TSV)ファイルの読み込みを行い、内容を返す def self.read(path) if File.extname(path) == ".csv" return CSV.read(path) elsif File.extname(path) == ".tsv" return CSV.read(path, col_sep: "\t") end end end
使ってみる
実際に動かしてみます。 動かすといっても、CSVの中身を標準出力に出すだけですが。
paths = Reader.get_paths paths.each do |path| p Reader.read(path) end
・実行結果
[["sales_no", "shop_cd", "customer_cd", "amount", "sales_date"], ["SAL0000001","SHOP001", "CUST001", "120000", "2016/03/01"] , ["SAL0000002", "SHOP001", "CUST001", "230000", "2016/03/02"], ["SAL0000003", "SHOP001", "CUST002", "340000", "2016/03/02"] , ["SAL0000004", "SHOP001", "CUST002", "450000", "2016/03/02"], ["SAL0000005", "SHOP002", "CUST030", "560000", "2016/03/04"]] [["sales_no", "shop_cd", "customer_cd", "amount", "sales_date"], ["SAL0000006","SHOP003", "CUST100", "980000", "2016/03/01"] , ["SAL0000007", "SHOP003", "CUST100", "760000", "2016/03/02"], ["SAL0000008", "SHOP003", "CUST100", "540000", "2016/03/02"] , ["SAL0000009", "SHOP003", "CUST100", "320000", "2016/03/02"], ["SAL0000010", "SHOP003", "CUST100", "100000", "2016/03/04"]]
ちゃんと読み込めることが確認できました。 せっかくなので、読み取ったデータをDBに突っ込んでみます。 DBに登録するにあたり、CSVの1行目ヘッダーの部分が邪魔なのでReaderクラスのreadメソッドを以下のように変更します。
def self.read(path) if File.extname(path) == ".csv" return CSV.read(path, headers: :first_row ) elsif File.extname(path) == ".tsv" return CSV.read(path, headers: :first_row, col_sep: "\t") end end
実行コードは次のようにして実行してみます。
paths = Reader.get_paths paths.each do |path| Reader.read(path).each do |row| p row end end
・実行結果
#<CSV::Row "sales_no":"SAL0000001" "shop_cd":"SHOP001" "customer_cd":"CUST001" "amount":"120000" "sales_date":"2016/03/01"> #<CSV::Row "sales_no":"SAL0000002" "shop_cd":"SHOP001" "customer_cd":"CUST001" "amount":"230000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000003" "shop_cd":"SHOP001" "customer_cd":"CUST002" "amount":"340000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000004" "shop_cd":"SHOP001" "customer_cd":"CUST002" "amount":"450000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000005" "shop_cd":"SHOP002" "customer_cd":"CUST030" "amount":"560000" "sales_date":"2016/03/04"> #<CSV::Row "sales_no":"SAL0000006" "shop_cd":"SHOP003" "customer_cd":"CUST100" "amount":"980000" "sales_date":"2016/03/01"> #<CSV::Row "sales_no":"SAL0000007" "shop_cd":"SHOP003" "customer_cd":"CUST100" "amount":"760000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000008" "shop_cd":"SHOP003" "customer_cd":"CUST100" "amount":"540000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000009" "shop_cd":"SHOP003" "customer_cd":"CUST100" "amount":"320000" "sales_date":"2016/03/02"> #<CSV::Row "sales_no":"SAL0000010" "shop_cd":"SHOP003" "customer_cd":"CUST100" "amount":"100000" "sales_date":"2016/03/04">
CSV.readにheaders: :first_rowオプションを追加すると、ヘッダーの値をキーとしたハッシュのような形にして返してくれました。 あとは、DBにデータを入れる処理を追加します。 MySQLの接続にmysql2を使うので、まだインストールしていない場合、下記コマンドでインストールしておきます。
>gem install mysql2
require 'mysql2' paths = Reader.get_paths client = Mysql2::Client.new(host: "localhost", username: "username", password: "password", database: "development_db") paths.each do |path| Reader.read(path).each do |row| sales_no = row["sales_no"] shop_cd = row["shop_cd"] customer_cd = row["customer_cd"] amount = row["amount"] sales_date = row["sales_date"] client.query("INSERT INTO sales (sales_no, shop_cd, customer_cd, amount, sales_date) VALUES ('#{sales_no}','#{shop_cd}','#{customer_cd}','#{amount}','#{sales_date}')") end end client.close
実行後、salesテーブルにデータが入っていることを確認します。
おわりに
CSVファイルの読み込みは使う機会も色々と多いと思いますので、覚えておいて損はないはずです。 rubyのリファレンスマニュアルを見てもcsvライブラリも何やら奥が深そうなので、もう少し簡単に書く方法もありそうです。