C#でのExcel読み書きライブラリのパフォーマンス比較

#比較対象のライブラリ
すでに比較されているサイトがあり、参考にします。  
C# の Excel ファイル操作ライブラリー
[https://creativeweb.jp/aspnet-oss/excel-tools/](https://creativeweb.jp/aspnet-oss/excel-tools/)  
この内3つのライブラリについて読み書き性能を比較します。
- NPOI
- EPPlus
- ExcelDataReader

※有償のライブラリはこの他にもあり、性能も優秀なので予算があればそちらをどうぞ。

比較サイトのテストには気になる点があります。書き込みテストと言っても、テスト内容はテンプレート的なファイルを読み込んでからセルに値を設定しファイル出力するものです。よってこの書き込みテスト結果は読み込み性能に引きずられている可能性があります。  
私の方でもテストを用意して比較してみました。テストのソースコードはこちらです。  
[https://github.com/shimitei/DotnetExcelExample](https://github.com/shimitei/DotnetExcelExample)

#読み込みテスト内容
よりセル数を増やしたテストを行います。読み込ませるExcelファイルは、郵便局のサイトから郵便番号データ(CSV)をダウンロードしたものを加工して使います。CSVファイルをExcelで開き、格子の罫線も引いてXLSX形式で保存します。  
データ数は123823行 x 15列 = 約186万セルです。  

#書き込みテスト内容
15列 x 1万行 = 15万セルをXLSXファイルに書き込みます。加えて、より実践的な書き込み処理とするために全セルに格子の罫線、全列に列幅の自動調整を行います。  
セルの内容は、文字列が5列、数値が5列、日付が5列です。内容はランダムなものですが、毎回同じデータを出力するように乱数の種を設定しています。

#テスト結果

| ライブラリ | バージョン | 読込処理時間 | 読込処理<br>メモリピーク | 書込<br>（15列 x 1万行） | 1万行書込<br>メモリピーク | 書込<br>（15列 x 10万行） | 10万行書込<br>メモリピーク |
|:----------|:-----------|-------------:|---------------------:|---------------------:|----------------------:|----------------------:|-----------------------:|
|ExcelDataReader|2.1.2.3|6,649|114,765,824|-|-|-|-|
|NPOI|2.1.3.1|15,859|1,071,607,808|49,181|91,422,720|508,798|679,505,920|
|EPPlus|4.0.5|16,197|322,125,824|4,450|75,993,088|43,962|389,931,008|

処理時間の単位はミリ秒、メモリピークはバイト（PeakWorkingSet）です。比較サイトでは処理時間のみ見ていましたが、データ数が多くなると使用メモリ量も気になるため計測しています。  
読み込みの結果はExcelDataReaderが最速で変わらず、メモリ使用量も最も少ないです。日本語処理の問題は、XLSX形式では見られませんでした。  
比較サイトと異なる結果になった要因としては、罫線と列幅の自動調整でしょうか。罫線やフォント等のスタイル設定には思いのほか処理時間がかかっています。

#結論
読み込みにはExcelDataReader、書き込みにはEPPlusを使いましょう。  

#出力100万行突破
たかだか数十万セル程度であればなんら問題なしですが、何故Excelシートに○○○万行も書くのでしょうね？ これOutOfMemoryなしに出力できたとしても読み込めないのでは...  
とりあえずExcelの闇に飲まれてみます。XLSXファイルは、拡張子は.xlsxでも中身はZIPファイルと同じ形式で、データはXMLに記述されています。このExcelのXML仕様は公開されているっぽいですが、分厚い仕様書を読んでいられない。その、MSオフィスのファイル仕様（Open XML Documents）を扱うためのライブラリOpen-XML-SDKもオープンソース化されているのですが、結構プリミティブ感があってちょっと触りたくないですね。  
さらに調べを進めると、Open-XML-SDKですらセル数が多くなるとファイル出力時にOutOfMemoryが出るという話らしく。これは詰んだな、と思ったところに救世主が登場。  
Open-Xml-PowerTools
[https://github.com/OfficeDev/Open-Xml-PowerTools](https://github.com/OfficeDev/Open-Xml-PowerTools)

一見はPowerShellでMSオフィスファイルを扱うモジュールですが、Open-XML-SDKのサンプル的位置づけの側面もあるようです。  
サポート機能の１つが神で、100万行級のXLSXファイル出力でもメモリの問題なく処理可能とあります。

> Writing XLSX files using far simpler code than directly writing the markup, including a streaming approach that enables writing XLSX files with millions of rows.

この機能に対応するソースコードはSpreadsheetWriter.csです。
機能が少ないから速いわけでもなく、Open-XML-SDKを利用するものの、XMLのツリー情報を保持しないように要所をバイパスして自前処理でXML出力を行うようになっています。  
それでも機能が少なくてしょぼいシートしか吐けないので、フォークして様々なスタイル設定に対応してみました。

[https://github.com/shimitei/Open-Xml-PowerTools/tree/cell-style](https://github.com/shimitei/Open-Xml-PowerTools/tree/cell-style)

対応しているスタイルや設定の仕方は、OpenXmlPowerToolsExamples/SpreadsheetWriterStyleプロジェクトを見てください。実行するといろいろExcelファイルが出力されます。

#NPOIでも100万行？
Apache POIにはいつの間にか[SXSSF (Streaming Usermodel API)](http://poi.apache.org/spreadsheet/how-to.html#sxssf)というAPIが追加されていて(POI 3.8 beta3から)、このSXSSFはNPOIでもサポートされているようです。ストリーミング処理することで制約はあるものの、あまりメモリを使用せずに出力が可能なようです。  
[http://poi.apache.org/spreadsheet/index.html](http://poi.apache.org/spreadsheet/index.html)  
こちらのページにPOIでのSXSSFの利点と制限事項が書かれています。NPOIでも同様かと思われます。