はじめに
- 本記事では、UiPath で巨大なCSVファイルをどう読み込むかについての筆者の実験・考察を扱います。
- 記事の内容は、個人の見解または確認結果であり、UiPath の公式見解ではありません。
- 製品仕様や参考画像は 23.10 バージョンのもので構成しています。
巨大なCSVを読み込むとどうなる?
32bit のアプリケーションでは一般的に問題なく動作するメモリの上限は2GBちょっとです。64bit だと4~5GB。
このため、巨大なCSVファイルを一気に読み込んだりすると
メモリ不足でシステムエラーが発生します。
どのくらいのボリュームで落ちるの?
A~AB(28)列で、平均10文字程度の半角英数字が入力されている前提で
200万レコード、ファイルサイズで550MB程度で落ちます。
500MB以上のCSVを読み込ませながらタスクマネジャーをみていただくとよいのですが、
私の手元では2900MBくらいまではロボットくんも頑張れました。
参考:メモリの消費量
どうやってメモリ不足のエラーを回避すればいい
方法1:プロセスを分離してみる
「ワークフロー呼び出し」の分離オプションをONにして実行する方法。
方法2:「Windows」プロジェクトにコンバートする
v21.10 以降、新しいランタイムプロジェクト(NET6のプロジェクト)として「Windows」プロジェクトが登場し、従来のプロジェクトが「Windows - レガシ」プロジェクトとなりました。
「Windows」プロジェクトは 64bit のランタイムとなるため、上でエラーとなっていた200万レコードのCSVも問題なく処理ができます。
標準パッケージのみで構成されているワークフローの場合、Windowsプロジェクトへのコンバートは比較的容易なため、メモリを多く消費するロボットは移行を検討いただいてもよいかもしれません。
ただし、この場合も5GB程度がメモリの上限となるため、それ以上消費するファイルに対しては有効な方法ではありません。
方法3:ストリームリーダーで1行ずつ処理する
# ストリームリーダーの使い方の補足
# ストリームリーダーの生成
ストリームリーダー = New StreamReader(New FileStream(ログファイルパス, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
# ストリームライターの生成
ストリームライター = New System.IO.StreamWriter("中間ファイル.csv",True)
# 繰り返しの中で1行読み込む
レコード = ストリームリーダー.ReadLine
# メソッド呼び出し
ストリームライター.Write(レコード)
手元の動作をみるに1時間でも終わらなそう?(最終アウトプットの半分のサイズを出力するのに30分かかっている)
方法4:CSVファイルの分割・読み込み
# PowerShellスクリプトでファイルを分割
"$i=1; Get-Content HugeCsvSample.csv -ReadCount 200000 | % { Out-File HugeCsvSample_$i.csv -InputObject $_; $i++ }"
が、しかしファイルを分割するため一括で検索できないのが難点。
方法5:File クラスで読み込む
# File クラスで読み込み
lines = File.ReadLines("HugeCsvSample.csv").where(Function(line) line.Contains("131"))
# メソッド呼び出し
System.IO.File.WriteAllLines("中間ファイル.csv",lines)
10秒です!!!実装の容易性と速さで秀でており、Where句の条件に関係なくパフォーマンスも出ます!
さいごに
いかがでしたでしょうか。
筆者の主観で利用条件を挙げるなら
- たまに大きいファイルを読むことがあるが、100~300MB程度である → 方法1(ワークフロー呼び出しの分離オプションを使ってみる)
- 恒常的に巨大ファイルが出現し、内容もまちまち → 方法2(「Windows」プロジェクトにコンバート)
- 巨大ファイルの読込部分のソース改修可能 → 方法5(File クラスで読み込む)
です!
巨大なデータファイルの読み込みでメモリ不足に遭遇した方の少しでもお役に立てば幸いです。
最後までお読みいただきありがとうございます(・ω・)ノ