この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。Yuraです。 前回に引き続き、Rubyネタです。 今回はRailsは使用しませんので、ご了承ください。
はじめに
Ruby学習の一環として、Rubyのyamlライブラリとcsvライブラリを使い、 ymlファイルに定義されているCSVの一覧から中身を読み取るプログラムを書いてみました。
環境
・OS Windows8.1 64bit ・Ruby 2.2.4p230 ・DB MySQL5.7
実装
読込対象ファイル
まず、ymlファイルに読み込みたいファイル名を記述します。 私はこんな感じで作りました。
csvList.yml
csv_folder: ./csv/ #CSV置場のディレクトリ
csv_files:
- test.csv #読み込みたいcsv名
- test.tsv #読み込みたいtsv名
CSVファイルは、テスト用にサンプル売上データを作りました。 今回はcsvファイルだけでなく、tsvファイルも読み込んでみるので、 tsvファイルも用意します。
test.csv
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
test.tsv
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と同じように扱えます。
reader.rb
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ライブラリも何やら奥が深そうなので、もう少し簡単に書く方法もありそうです。