こんにちは。
キャスレーコンサルティングの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を超えるサイズになることが想定される場合などは
範囲をきめてファイルを分けるか、データの持ち方自体検討する必要があります。

終わりに

最後までお読み頂き、ありがとうございました。


こんにちは、キャスレーコンサルティングSI部の清水です。

Railsでは、Rails 3.1よりクライアントサイド開発の言語としてCoffeeScript/SCSSを標準サポートしています。
CoffeeScript/SCSSは簡単に言うとJavaScript/CSSをより便利に、シンプルにするための言語で、
必ずしも使用しなければならないということはありませんが、生産性の高さから考えるとぜひ押さえておきたい言語です。
今回はAsset Pipeという機能を活用し、簡単なCoffeeScriptを試してみたいと思います。 (続きを読む…)


こんにちは、キャスレーコンサルティングSI部の清水です。

今回はすでに業務で使われている方が多いかもしれませんが、Ruby on Railsの紹介をいたします。

Ruby on Railsは近年、アプリケーションのベース構成の大半はRailsコマンドにて自動生成できることから、開発工数の削減、開発スピードアップという利点で現在では多くの業務Webアプリに採用されるようになってきました。

そんな今ではメジャーとなったRuby on Railsですが、まだ触れたことのない方向けに、Windows環境にてインストールから実際に動く簡単なWebアプリの作成を実演します。

(続きを読む…)



  • Profile
    キャスレーコンサルティングの技術ブログです。
    当社エンジニアが技術面でのTips、技術系イベント等についてご紹介いたします。
  • CSV社長ブログ
  • チーム・キャスレーブログ