.NET のサービスから Excel レポートを生成しようとした人、もしくはスプレッドシートを取り込もうとした人なら、おそらく同じ壁に突き当たったはずです。Microsoft.Office.Interop.Excel を使うには Office のインストールが必要で、サーバーでは動かず、ヘッドレス環境やコンテナ環境ではサポートされません。

本記事では、C# で .xlsx を扱うための実用的な選択肢を整理します。それぞれのライブラリが何に向いていて、どこに落とし穴があるのか、そして「どのケースにどれを選ぶべきか」を解説します。


なぜ Office Interop ではダメなのか

Microsoft.Office.Interop.Excel は COM を介して実物の Excel プロセスを自動操作します。開発者のマシンでは動くものの、本番環境ではほぼすべてのシナリオで不適切です。

  • ホストに Excel がインストールされている必要がある
  • Microsoft 自身がサービスや Web アプリでの利用をサポートしていない(KB257757)
  • 呼び出しのたびに COM 境界を越えるため遅い
  • クラッシュした Excel プロセスが残り、徐々に蓄積していく

サーバーサイドやクロスプラットフォームのコードでは、OpenXML の .xlsx 形式を 直接 読み書きするライブラリを選ぶのが基本方針になります。


候補一覧

ライブラリライセンス用途
OpenXML SDKMITOpenXML パーツの低レベル読み書き
ClosedXMLMITOpenXML SDK をラップした高レベル API
EPPlusPolyform Noncommercial / 商用高機能な xlsx・グラフ・ピボット。v5 以降は 商用利用は有償
NPOIApache 2.0Java POI の移植版。レガシーな .xls.xlsx の両方を扱える
ReoGridフリー / 商用WinForms / WPF で 同じファイルを読み書きしつつ表示・編集 できる

正解は、「単に解析するだけ」なのか「ユーザーに表示する必要もある」のかで決まります。


ワークブックを読み込む

invoices.xlsx の最初のシートのすべての行を出力したい、というケースを想定します。

OpenXML SDK(低レベル)

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

using var doc = SpreadsheetDocument.Open("invoices.xlsx", false);
var sheet = doc.WorkbookPart!.Workbook.Sheets!.Elements<Sheet>().First();
var part  = (WorksheetPart)doc.WorkbookPart.GetPartById(sheet.Id!);
var rows  = part.Worksheet.Descendants<Row>();

foreach (var row in rows)
{
    foreach (var cell in row.Elements<Cell>())
    {
        Console.Write(cell.CellValue?.Text + "\t");
    }
    Console.WriteLine();
}

Microsoft 公式の無償ライブラリですが、ほとんどの時間を「フォーマットとの戦い」に費やすことになります。共有文字列、インデックス指定のスタイル、インライン文字列など。ビット単位の制御が必要なとき に向いています。

ClosedXML(高レベルラッパ)

using ClosedXML.Excel;

using var book = new XLWorkbook("invoices.xlsx");
var sheet = book.Worksheet(1);

foreach (var row in sheet.RowsUsed())
{
    foreach (var cell in row.CellsUsed())
    {
        Console.Write(cell.GetString() + "\t");
    }
    Console.WriteLine();
}

これが多くの人にとって「欲しい体験」のはずです。トレードオフは、ClosedXML がワークブック全体をメモリに読み込むため、非常に大きいファイル ではストリーミング系のリーダより遅くなる点です。

ReoGrid(表示も伴うとき)

using unvell.ReoGrid;

var book = ReoGridControl.CreateMemoryWorkbook();
book.Load("invoices.xlsx");

var sheet = book.Worksheets[0];
for (int r = 0; r <= sheet.MaxContentRow; r++)
{
    for (int c = 0; c <= sheet.MaxContentCol; c++)
    {
        Console.Write(sheet[r, c] + "\t");
    }
    Console.WriteLine();
}

WinForms / WPF のグリッドコントロールにバインドするのと 同じワークブックオブジェクト なので、別途「ビューモデル層」を持たなくて済みます。


ワークブックを書き出す

逆に、ヘッダー行・数行のデータ・Excel 数式を含む小さなレポートを生成してみます。

ClosedXML

using var book = new XLWorkbook();
var sheet = book.Worksheets.Add("Report");

sheet.Cell("A1").Value = "Product";
sheet.Cell("B1").Value = "Units";
sheet.Cell("C1").Value = "Price";
sheet.Cell("D1").Value = "Total";
sheet.Range("A1:D1").Style.Font.Bold = true;

sheet.Cell("A2").Value = "Widget";
sheet.Cell("B2").Value = 12;
sheet.Cell("C2").Value = 9.99;
sheet.Cell("D2").FormulaA1 = "=B2*C2";

book.SaveAs("report.xlsx");

ReoGrid

var book = ReoGridControl.CreateMemoryWorkbook();
var sheet = book.CreateWorksheet("Report");
book.Worksheets.Add(sheet);

sheet["A1"] = new object[] { "Product", "Units", "Price", "Total" };
sheet.Ranges["A1:D1"].Style.Bold = true;

sheet["A2"] = new object[] { "Widget", 12, 9.99 };
sheet["D2"] = "=B2*C2";

book.Save("report.xlsx");

どちらも、列幅・塗りつぶし・罫線・数値書式・結合セルなどは想定どおりに扱えます。最大の違いは、ReoGrid は内蔵の 数式エンジン で書き出し時に数式を評価するため、ファイルがディスクに着地した時点で D2 には既に 119.88 が入っている、という点です。ClosedXML でキャッシュ値が必要な場合は、事前に book.RecalculateAllFormulas() を呼ぶ必要があります。


非常に大きなファイルへの対応

メモリにすべてを乗せられないケースでは、次のような手段があります。

  • OpenXML SDK にはストリーミング向けの OpenXmlReader があります。記述量は多いですが省メモリです。
  • EPPlus は、行を追記するごとにフラッシュするストリーミング書き込み API を備えています。
  • ReoGrid 4.4 では、20 万セル規模の一括ロードがセル単位の代入比で約 3 倍速い SetRangeData が追加されています。実測値は v4.4 リリースノート を参照してください。

経験則: 5 万行以下 ならフレンドリーな API で十分。それ以上はストリーミングを検討してください。


ライブラリの選び方

簡単な意思決定ガイド:

  • 既知フォーマットの xlsx をパースしたいだけ? → ClosedXML か NPOI。MIT / Apache で扱いやすい。
  • OpenXML 内部を完全に制御したい? → OpenXML SDK。
  • デスクトップアプリで表示・編集も行いたい? → ReoGrid(または他のスプレッドシート UI コントロール)。
  • サーバーでグラフ・ピボット・条件付き書式まで使いたい? → EPPlus(商用ライセンス必要)または ReoGrid。
  • .xls.xlsx を併用? → レガシー .xls を一級市民として扱えるのは NPOI のみ。

すべての軸で勝つ単一のライブラリはありません。サービス内でのヘッドレスなレポート生成なら ClosedXML がほぼ最適です。デスクトップアプリで「同じワークブックを読み込み・編集・保存する」なら、読み書きと UI を 1 つのライブラリで こなせる選択肢のほうが、2 つを糊で繋ぐよりずっと少ないコードで済みます。


さらに読む