目次
概要
OSSライブラリ「NPOI」を使用し、作成したExcelシートの特定のセルに値を設定する実装です。
行(Row)を作成してから、その中にセル(Cell)を確保して値を書き込むというNPOI特有の手順をラッパークラスで簡略化し、ループ処理などで効率的にデータを埋め込めるようにします。
仕様(入出力)
- 入力: 保存先パス、シート名、書き込みたいデータ
- 出力: データが入力された
.xlsxファイル - ライブラリ: NPOI (NuGetパッケージ)
実装メソッド
| メソッド名 | 説明 |
CreateRow | シート内の指定したインデックス(0始まり)に行を作成し、その行オブジェクト(IRow)を返します。 |
SetCellValue | 渡された行オブジェクト内の指定列にセルを作成し、値を設定します。 |
基本の使い方
// インスタンス生成
var excel = ExcelWriter.Create("matrix.xlsx");
excel.AddSheet("ScoreData");
// 0行目を作成
var row = excel.CreateRow(0);
// (0, 0) と (0, 1) に値をセット
excel.SetCellValue(row, 0, "Alice");
excel.SetCellValue(row, 1, "95");
excel.Save();
コード全文
このコードを実行するには dotnet add package NPOI が必要です。
using System;
using System.IO;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
class Program
{
static void Main()
{
try
{
// 1. Excel操作クラスの初期化
Console.WriteLine("Generating Excel file...");
var writer = ExcelWriter.Create("GridData.xlsx");
// 2. シートの追加
writer.AddSheet("MultiplicationTable");
// 3. ループ処理による値の書き込み
// NPOIでは「行」を取得/作成してから、その行内の「セル」を操作します
for (int r = 0; r < 9; r++)
{
// 行オブジェクト(IRow)を作成
// 行番号は0始まり(0=Excelの1行目)
IRow currentRow = writer.CreateRow(r);
for (int c = 0; c < 9; c++)
{
// 九九の計算結果を文字列として書き込み
var value = $"{r + 1} x {c + 1} = {(r + 1) * (c + 1)}";
writer.SetCellValue(currentRow, c, value);
}
}
// 4. 保存
writer.Save();
Console.WriteLine("File saved successfully.");
}
catch (IOException ex)
{
Console.WriteLine($"File Access Error: {ex.Message}");
}
}
}
/// <summary>
/// NPOIのセル操作をラップするクラス
/// </summary>
public sealed class ExcelWriter
{
private readonly XSSFWorkbook _workbook;
private ISheet _currentSheet;
private string _filePath;
private ExcelWriter()
{
_workbook = new XSSFWorkbook();
}
/// <summary>
/// 指定パスで保存するためのインスタンスを作成します
/// </summary>
public static ExcelWriter Create(string filePath)
{
return new ExcelWriter { _filePath = filePath };
}
/// <summary>
/// 新しいシートを作成し、操作対象として設定します
/// </summary>
public void AddSheet(string sheetName)
{
_currentSheet = _workbook.CreateSheet(sheetName);
}
/// <summary>
/// 指定した行番号に行を作成し、そのオブジェクトを返します
/// </summary>
/// <param name="rowIndex">行インデックス(0開始)</param>
/// <returns>作成された行オブジェクト</returns>
public IRow CreateRow(int rowIndex)
{
// シートが未作成の場合は例外またはデフォルトシート作成などの対応が必要
if (_currentSheet == null)
{
throw new InvalidOperationException("Sheet must be created before adding rows.");
}
return _currentSheet.CreateRow(rowIndex);
}
/// <summary>
/// 指定した行・列に文字列の値を設定します
/// </summary>
/// <param name="row">対象の行オブジェクト</param>
/// <param name="columnIndex">列インデックス(0開始)</param>
/// <param name="value">設定する文字列</param>
public void SetCellValue(IRow row, int columnIndex, string value)
{
// セルを作成(既に存在する場合はGetCell等の判定が必要だが、新規作成前提とする)
var cell = row.CreateCell(columnIndex);
cell.SetCellValue(value);
}
/// <summary>
/// ファイルを保存します
/// </summary>
public void Save()
{
using var fs = new FileStream(_filePath, FileMode.Create, FileAccess.Write);
_workbook.Write(fs);
}
}
カスタムポイント
- 数値や日付の対応:現在の
SetCellValueは文字列のみ受け取っていますが、オーバーロードを作成してdoubleやDateTimeを受け取り、cell.SetCellValue((double)value)のように型に合わせて呼び出すと、Excel上で数値として計算可能になります。 - 既存行の取得:
CreateRowは新規作成を行いますが、既存の行に追記したい場合は_currentSheet.GetRow(rowIndex) ?? _currentSheet.CreateRow(rowIndex)のように、取得を試みてから作成するロジックに変更してください。
注意点
- 行オブジェクトの再利用:
CreateRowは同じ行番号に対して2回呼び出すと、以前の行データを上書き(クリア)してしまいます。同じ行に複数のセルを追加する場合は、コード例のように「行オブジェクトを変数に保持」して使い回してください。 - インデックスの上限:Excel 2007以降(.xlsx)の仕様では最大行数は1,048,576行、最大列数は16,384列です。これを超えるインデックスを指定するとエラーにはなりませんが、Excelで開けなくなる可能性があります。
- パフォーマンス:NPOIはセルの数だけオブジェクトをメモリに生成します。数万行を超えるデータを扱う場合、GC(ガベージコレクション)が頻発して遅くなることがあります。
応用
数値型に対応したオーバーロードの追加
数値を文字列としてではなく、計算可能な数値データとして埋め込む拡張です。
// ExcelWriterクラスに追加
public void SetCellValue(IRow row, int columnIndex, double value)
{
var cell = row.CreateCell(columnIndex);
// 数値としてセット(Excel側でSUMなどが可能になる)
cell.SetCellValue(value);
}
まとめ
NPOIでのセル書き込みは「ブック → シート → 行 → セル」という階層構造を順に生成していく必要があります。特にループ処理を行う際は、行(IRow)の生成を外側のループで行い、内側のループでセル(ICell)を埋めていく構造にすることで、オブジェクトの生成コストを抑えつつ直感的なコード記述が可能になります。
