はじめに
Ruby で CSV を扱う方法をいつも忘れるので、備忘録として記事にして残しておこうと思います。Claude Code や Cursor が何でも実装してくれる世界になってしまいましたが、発信することや備忘録を残しておくことは良いことだと思うので。
Ruby の CSV クラスについてこちら docs.ruby-lang.org
AWS の S3 にある CSV を取得して扱う
AWS S3 上にある CSV を取得して処理をする場合は一般的に AWS SDK for Ruby を利用するので、その前提で記述します。
以下のコードで client を初期化して、S3 にある CSV を取得してきます。
# SDKを用いたS3アクセス用のclientインスタンス初期化(もしくはアクセスキーを発行して、初期化するか) client = Aws::S3::Client.new(region: "ap-northeast-1") # S3からオブジェクトを取得 s3_object = client.get_object(bucket: "your-bucket", key: "path/to/your_csv_file.csv").body
AWS SDK for Ruby のドキュメントはこちら docs.aws.amazon.com
CSV の読み込み系メソッドの比較
CSV クラスにおける代表的な読み込みメソッドについて比較をします。 Benchmark の数値を記述していますが、上が 1 万行の CSV で下が 10 万行の CSV の場合です。
foreach(ファイルから一行ずつ)
用途
他のメソッドと違って一括で全てメモリに展開するわけではないので、メモリ不足に陥らずに使えるようです。大規模な CSV を扱いたい時などに使います。
# s3_object [StringIO] S3のCSVデータを保持しているStringIOオブジェクト CSV.foreach(s3_object, headers: true) { |row| p row } # row #<CSV::Row "id":"1"> # Benchmark # user system total real # 0.062323 0.037299 0.099622 ( 0.099879) (1万行) # 0.380158 0.233433 0.613591 ( 0.613826) (10万行)
parse × each(文字列から一行ずつ)
用途
文字列や IO を一括でパースして扱いたい場合に利用します。一括でメモリに載せます。
# s3_object [StringIO] S3のCSVデータを保持しているStringIOオブジェクト CSV.parse(s3_object, headers: true).each { |row| p row } # row #<CSV::Row "id":"1"> # Benchmark # user system total real # 0.062451 0.030136 0.092587 ( 0.092584) # 0.366748 0.144115 0.510863 ( 0.510955)
read × each(ファイルから一度に)
用途
ファイルや IO をそのまま読み込み、テーブルとして扱います。一括でメモリに載せます。
# s3_object [StringIO] S3のCSVデータを保持しているStringIOオブジェクト CSV.read(s3_object, headers: true).each { |row| p row } # row #<CSV::Row "id":"1"> # Benchmark # user system total real # 0.062829 0.022257 0.085086 ( 0.085019) # 0.340553 0.131258 0.471811 ( 0.471852)
まとめ
Ruby での CSV の取り扱いについてまとめました。
StringIO とheaders: trueを渡せば、どれも row[(attr_name)]で値を取り出すことが可能なので、この場合の使い方にはあまり違いがなさそうですね。
parseとreadの違いは自分もそこまできちんと分かっているわけではありませんが、foreachとparse / readは速度を取るか、メモリを節約するかのトレードオフになりそうです。
いつどこでメモリをどのくらい消費しているかみたいなのは今回測定していません。
余談
CSV gem の変化について
CSV は今までは default gem でしたが、Ruby 3.4 からは bundled gem に変更されたようです。つまり、以前までと違って Gemfile に明記しないと動かなくなるということです。場合によっては、以下のような警告が出ることもあります。
warning: /usr/local/lib/ruby/3.3.0/csv.rb was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.4.0. You can add csv to your Gemfile or gemspec to silence this warning.
default gem と bundled gem についてや公式こちらを参照ください。
徹底解説! default gems と bundled gems のすべて gihyo.jp
標準ライブラリのアップデート - Ruby 3.4.0 リリース www.ruby-lang.org
StringIO を扱えるようになった件
CSV はどこかのバージョンまでは StringIO を渡しても動かなかったのですが、以下の Pull Request で動くようになったようです。
自分も以前からパスだけではなく IO や StringIO を渡せるようになれば良いのになぁと思っていたんですが、もうすでにその変更は入っていたようです。
感謝。