YASD-TECH
YASD TECH
# Ruby

CSV

投稿日:2026/7/24

更新日:2026/7/24

ttitleImage

CSV の扱い方(read / foreach / parse)

RubyでCSVを扱うときの CSV.read / CSV.foreach / CSV.parse の使い分けと、メモリ・パフォーマンス上の注意点のまとめ。

CSV はRubyの標準ライブラリcsv gem)で、Railsがなくても require "csv" すれば素のRubyスクリプトで使える。CSVをパース・生成するロジックそのものはRubyの機能で、Railsはそれをアップロード受付やダウンロード提供(send_data など)に組み合わせて使っているだけ、という分担で捉えるとよい。

3メソッドの比較

メソッド 入力 戻り値 メモリ 主な用途
CSV.read ファイルパス 全行の配列(Array<Array> or CSV::Table 全読み込み 小〜中規模ファイルを一括で扱う
CSV.foreach ファイルパス なし(1行ずつyield) ストリーミング 大規模ファイルを逐次処理
CSV.parse 文字列 全行の配列 or ブロックでyield 文字列次第 すでにメモリ上にある文字列をパース

CSV.read — ファイル全体をメモリに載せる

rows = CSV.read("data.csv")
# => [["id", "name"], ["1", "Alice"], ["2", "Bob"]]

# headers: true なら CSV::Table を返す
table = CSV.read("data.csv", headers: true)
table.each { |row| puts row["name"] }

全行を配列として保持するため、ファイルサイズにほぼ比例してメモリを消費する。ランダムアクセスや、全体に対するソート・集計を行いたいときに向く。

CSV.foreach — 1行ずつ処理(メモリ効率が最良)

CSV.foreach("data.csv", headers: true) do |row|
  puts row["name"]
end

内部でファイルを開いて1行ずつyieldするので、ファイルが何GBあっても一定メモリで処理できる。大規模データのETLや変換処理はこれが第一候補。CSV.read は内部的に foreach で組み立てているようなものと考えるとよい。

CSV.parse — 文字列を対象にする

csv_string = "id,name\n1,Alice\n2,Bob\n"

# 配列で受け取る(全部メモリに載る)
rows = CSV.parse(csv_string, headers: true)

# ブロックを渡すと1行ずつyield(メモリ節約)
CSV.parse(csv_string, headers: true) do |row|
  puts row["name"]
end

APIレスポンスやDBから取り出した文字列など、ファイルではなく既にメモリ上にあるCSVデータを扱うときに使う。ブロックを渡すかどうかでメモリ挙動が変わる点に注意。


メモリ・パフォーマンス上の注意点

1. 「一括読み込み」系は大規模ファイルで危険

CSV.read とブロックなしの CSV.parse は全行を配列化するため、大きなファイルで容易にメモリを食い潰す。行数が読めない・大きい場合は CSV.foreach かブロック付き CSV.parse を使う。

2. ファイル全体を文字列に読んでから parse しない

# アンチパターン: ファイル読み込み(全メモリ) + パース(全メモリ) で二重に消費
CSV.parse(File.read("huge.csv"))

# 良い: ストリーミング
CSV.foreach("huge.csv") { |row| ... }

3. headers: true にはオーバーヘッドがある

各行を CSV::Row オブジェクト(ヘッダ名でアクセス可能)として生成するため、単純な配列より処理コスト・メモリが増える。列名アクセスの利便性が要らない超高速処理では headers: false(デフォルト)+添字アクセスの方が速い。

4. converters は必要な範囲だけに

CSV.foreach("data.csv", converters: :numeric) { |row| ... }

:numeric:all は各セルを型変換しようとするため、行数が多いと効いてくる。必要な列だけ自前で変換する方が速いことも多い。

5. エンコーディングを明示する

CSV.foreach("data.csv", encoding: "UTF-8") { |row| ... }
# BOM付きUTF-8なら "bom|utf-8"

文字化けや Invalid byte sequence を避けるため、扱うファイルのエンコーディングは明示するのが安全。

6. 壊れたCSVには liberal_parsing

CSV.foreach("dirty.csv", liberal_parsing: true) { |row| ... }

クォートが不正な行などで CSV::MalformedCSVError を出さずに処理を継続したい場合に使う。


使い分けの指針(まとめ)

  • 大規模ファイル / 行単位の逐次処理CSV.foreach(一定メモリ)
  • 小〜中規模で全体を配列として扱いたいCSV.read
  • 文字列データをパースCSV.parse(大きいならブロック付きで)
  • 迷ったら foreach をデフォルトにしておくとメモリ事故を避けやすい

補足: require "csv" の位置づけ

Ruby 3.3以前は csv はデフォルトgemとして同梱されていたが、Ruby 3.4以降はbundled gem扱いになり、Gemfileへの明示が必要になるケースがある。Railsプロジェクトなら依存として入っていることが多いが、素のスクリプトで LoadError が出たら gem install csv / Gemfileへの追加を検討する。

Index

  • CSV の扱い方(read / foreach / parse)
  • 3メソッドの比較
  • CSV.read — ファイル全体をメモリに載せる
  • CSV.foreach — 1行ずつ処理(メモリ効率が最良)
  • CSV.parse — 文字列を対象にする
  • メモリ・パフォーマンス上の注意点
  • 1. 「一括読み込み」系は大規模ファイルで危険
  • 2. ファイル全体を文字列に読んでから parse しない
  • 3. headers: true にはオーバーヘッドがある
  • 4. converters は必要な範囲だけに
  • 5. エンコーディングを明示する
  • 6. 壊れたCSVには liberal_parsing
  • 使い分けの指針(まとめ)
  • 補足: require "csv" の位置づけ