投稿日:2026/7/24
更新日:2026/7/24

RubyでCSVを扱うときの CSV.read / CSV.foreach / CSV.parse の使い分けと、メモリ・パフォーマンス上の注意点のまとめ。
CSV はRubyの標準ライブラリ(csv gem)で、Railsがなくても require "csv" すれば素のRubyスクリプトで使える。CSVをパース・生成するロジックそのものはRubyの機能で、Railsはそれをアップロード受付やダウンロード提供(send_data など)に組み合わせて使っているだけ、という分担で捉えるとよい。
| メソッド | 入力 | 戻り値 | メモリ | 主な用途 |
|---|---|---|---|---|
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データを扱うときに使う。ブロックを渡すかどうかでメモリ挙動が変わる点に注意。
CSV.read とブロックなしの CSV.parse は全行を配列化するため、大きなファイルで容易にメモリを食い潰す。行数が読めない・大きい場合は CSV.foreach かブロック付き CSV.parse を使う。
parse しない# アンチパターン: ファイル読み込み(全メモリ) + パース(全メモリ) で二重に消費
CSV.parse(File.read("huge.csv"))
# 良い: ストリーミング
CSV.foreach("huge.csv") { |row| ... }
headers: true にはオーバーヘッドがある各行を CSV::Row オブジェクト(ヘッダ名でアクセス可能)として生成するため、単純な配列より処理コスト・メモリが増える。列名アクセスの利便性が要らない超高速処理では headers: false(デフォルト)+添字アクセスの方が速い。
converters は必要な範囲だけにCSV.foreach("data.csv", converters: :numeric) { |row| ... }
:numeric や :all は各セルを型変換しようとするため、行数が多いと効いてくる。必要な列だけ自前で変換する方が速いことも多い。
CSV.foreach("data.csv", encoding: "UTF-8") { |row| ... }
# BOM付きUTF-8なら "bom|utf-8"
文字化けや Invalid byte sequence を避けるため、扱うファイルのエンコーディングは明示するのが安全。
liberal_parsingCSV.foreach("dirty.csv", liberal_parsing: true) { |row| ... }
クォートが不正な行などで CSV::MalformedCSVError を出さずに処理を継続したい場合に使う。
CSV.foreach(一定メモリ)CSV.readCSV.parse(大きいならブロック付きで)foreach をデフォルトにしておくとメモリ事故を避けやすいrequire "csv" の位置づけRuby 3.3以前は csv はデフォルトgemとして同梱されていたが、Ruby 3.4以降はbundled gem扱いになり、Gemfileへの明示が必要になるケースがある。Railsプロジェクトなら依存として入っていることが多いが、素のスクリプトで LoadError が出たら gem install csv / Gemfileへの追加を検討する。