こんにちは。
キャスレーコンサルティングのSI(システムインテグレーション)部の田中(雅)です。
Rubyを利用して、CSV,XML,JSON でのファイル出力・入力について考察していきます。
プログラムを組む時に、どの形式のファイルにするかなどを決める際の、参考にして頂ければ幸いです。
開発環境
今回は、「Cloud9」で作成しました。
以下、作成された環境のversionを確認したものです。
ruby 2.3
Rails 5.0.3
mysql 5.5.54
プログラムだけの勉強などをしたい時は、非常に簡単に環境ができるので便利ですね。
作成したプログラムファイル
railsのプロジェクトルートディレクトリ
└lib
└tasks
└output_csv.rb–CSV出力プログラム
└output_xml.rb–XML出力プログラム
└output_json.rb–JSON出力プログラム
└read_csv.rb–CSV入力プログラム
└read_xml.rb–XML入力プログラム
└read_json.rb–JSON入力プログラム
CSVファイルを出力
名前(name)、年齢(age)、性別(sex)
という簡単な構造のテーブルからSELECTを行い、CSVファイルとして出力する処理になります。
事前にこのテーブルに、10,000件のレコードを登録しておきます。
output_csv.rb
require "csv" class Tasks::OutputCsv def self.execute # DBからデータ取得 sample_data = DataFileSample.all # ファイル出力 csv_doc = CSV.open('output/test.csv', 'w') csv_doc.puts ["name", "age", "sex"] # DBから取得したデータを1件ずつCSVに追加 for row_data in sample_data do csv_doc.puts [row_data.name, row_data.age, row_data.sex] end end end
これでoutputディレクトリの配下に、test.csvというファイルが作成されます。
name,age,sex
キャスレー1,65,男
キャスレー2,81,女
キャスレー3,82,男
キャスレー4,81,女
キャスレー5,70,男
キャスレー6,42,女
キャスレー7,12,男
キャスレー8,29,女
キャスレー9,73,男
・
・
XMLファイルを出力
CSVファイルの出力と同じテーブルを使用しますが、
XML形式の場合、階層構造を作る必要がある為、若干コード量が増えます。
output_xml.rb
require 'rexml/document' require 'rexml/formatters/pretty' class Tasks::OutputXml def self.execute xmldoc = REXML::Document.new xmldoc << REXML::XMLDecl.new('1.0', 'UTF-8') # ルートノードを作成 root = REXML::Element.new('datas') xmldoc.add_element(root) # 子ノードを作成 child = REXML::Element.new('data') # DBからデータ取得 sample_data = DataFileSample.all # DBから取得したデータを1件ずつXMLに追加 for row_data in sample_data do child.add_element("name").add_text(row_data.name) child.add_element("age").add_text("#{row_data.age}") child.add_element("sex").add_text(row_data.sex) end root.add_element(child) # ファイル出力 File.open('output/test.xml', 'w') do |file| xmldoc.write(file, 2) end end end
こちらもoutputディレクトリ配下に、test.xmlという名前で作成されます。
<?xml version='1.0' encoding='UTF-8'?> <datas> <data> <name> キャスレー1 </name> <age> 65 </age> <sex> 男 </sex> <name> キャスレー2 </name> <age> 81 </age> ・ ・
何も指定しないと、改行してしまうんですね。。
JSONファイルを出力
CSVファイルの出力と、同じテーブルを使用します。
こちらも階層構造を作る必要はありますが、ハッシュにしてしまえば使えるので比較的簡単です。
output_json.rb
class Tasks::OutputJson def self.execute json_array = [] # DBからデータ取得 sample_data = DataFileSample.all # DBから取得したデータを1件ずつ配列に追加 for row_data in sample_data do json_row = {} json_row[:name] = row_data.name json_row[:age] = row_data.age json_row[:sex] = row_data.sex json_array.push(json_row); end # 整形 json_str = JSON.pretty_generate(json_array) # ファイル出力 File.open('output/test.json', 'w') do |file| file.puts(json_str) end end end
こちらもoutputディレクトリ配下に、test.jsonという名前で作成されます。
[ { "name": "キャスレー1", "age": 65, "sex": "男" }, { "name": "キャスレー2", "age": 81, "sex": "女" }, { "name": "キャスレー3", "age": 82, "sex": "男" }, ・ ・
それぞれのファイルサイズ
それぞれ、ファイル作成した時のサイズは
CSV = 0.26MB
XML = 1.1MB
JSON = 0.73MB
となりました。
CSVが1番小さく、XMLの4分の1以下ですね。
それでは、これらのファイルを読み込んだ時のメモリ使用量を見てみましょう!
CSVファイルを入力
上で作成したtest.csvを、プログラムで読み込みメモリ使用量をプリントします。
read_csv.rb
require 'csv' require 'objspace' class Tasks::ReadCsv def self.execute data_list = CSV.read('output/test.csv') # 読み込んだCSVのサイズ puts "#{ObjectSpace.memsize_of_all} B" end end
プロジェクトルートディレクトリからコマンド実行
$ rails runner Tasks::ReadCsv.execute
Running via Spring preloader in process 2981
26317626 B
という結果が出力されました。
XMLファイルを入力
上で作成したtest.xmlをプログラムで読み込み、メモリ使用量をプリントします。
read_xml.rb
require 'rexml/document' require 'objspace' class Tasks::ReadXml def self.execute # XMLファイルの読み込み xmldoc = REXML::Document.new(open("output/test.xml")) # 読み込んだXMLのサイズ puts "#{ObjectSpace.memsize_of_all} B" end end
プロジェクトルートディレクトリからコマンド実行
$ rails runner Tasks::ReadXml.execute
Running via Spring preloader in process 2994
74746687 B
という結果が出力されました。
JSONファイルを入力
上で作成したtest.jsonをプログラムで読み込み、メモリ使用量をプリントします。
read_json.rb
require 'json' require 'objspace' class Tasks::ReadJson def self.execute json_hash = {} # Jsonファイルの読み込み File.open('output/test.json') do |file| json_hash = JSON.load(file) end # 読み込んだJSONのサイズ puts "#{ObjectSpace.memsize_of_all} B" end end
プロジェクトルートディレクトリからコマンド実行
rails runner Tasks::ReadJson.execute
Running via Spring preloader in process 3008
33209782 B
という結果が出力されました。
各ファイル形式のファイルの読み込み
こちらで、作成したファイルを読み込んだ時のメモリサイズは
CSV = 25.1MB
XML = 71.2MB
JSON = 31MB
となりました。
考察
CSVはファイル自体は、JSONの2倍以上ありますが
メモリのサイズを見ると、JSONより若干小さい程度になっており
予想と異なる結果になりました。
使用するデータ構造にもよりますが、
簡易な構造のデータであれば、JSONが使いやすく
かつ、軽く使える形式かと考えられます。
もちろん、サーバースペックも関係しますし
10MBを超えるサイズになることが想定される場合などは
範囲をきめてファイルを分けるか、データの持ち方自体検討する必要があります。
終わりに
最後までお読み頂き、ありがとうございました。