コンソールアプリケーション、クラスライブラリで多言語化対応(ローカライズ)する や WPFで多言語化対応(ローカライズ)する でリソースの内容を直接リソースファイルに記述していたのですが、さすがに数が多すぎて管理しにくくなったのでエクセルからリソースファイルを作成するようにしました。
エクセルを読み込むライブラリとして最初はMicrosoft.Office.Interop.Excelを使用しようと考えていたのですが、実行するPCにエクセルがインストールされていないと駄目だということで候補から除外しました。エクセルがインストールしてあるPCとは限らないので念のためにです。
ということで今回はClosedXMLというライブラリを使用していきます。
環境
- .NET 7
- Windows10 Pro
- Visual Studio 2022 v17.6.0 Preview 1.0
- ClosedXML 0.101.0
GitHub
https://github.com/ClosedXML/ClosedXML
NuGet
https://www.nuget.org/packages/ClosedXML/
エクセルを新規作成、保存する
XLWorkbook book = new XLWorkbook();
// シートを追加
var sheet1 = book.AddWorksheet();
sheet1.Name = "シート名_1";
// 名前を付けて保存
book.SaveAs("test.xlsx");
シートを追加せずに保存しようとすると以下のエラーが発生します。
空のファイルを作る場合は注意しましょう。
System.InvalidOperationException: Workbooks need at least one worksheet.
at ClosedXML.Excel.XLWorkbook.checkForWorksheetsPresent()
at ClosedXML.Excel.XLWorkbook.SaveAs(String file, SaveOptions options)
at ClosedXML.Excel.XLWorkbook.SaveAs(String file, Boolean validate, Boolean evaluateFormulae)
at ClosedXML.Excel.XLWorkbook.SaveAs(String file)
at ClosedXMLTest.ClosedXMLTest.CreateNew() in C:\ClosedXMLTest\ClosedXMLTest\ClosedXMLTest.cs:line 33
at ClosedXMLTest.ClosedXMLTest.Main(String[] args) in C:\ClosedXMLTest\ClosedXMLTest\ClosedXMLTest.cs:line 16
シートを追加、挿入、削除する
新規作成の時に既に行っていますが、AddWorksheet()でシートを追加が可能です。
Sheet.Positionで位置を変更可能です。
以下の例ではシート1とシート3の間へのシート2の挿入とシート1の前にシート4を挿入してから削除しています。
XLWorkbook book = new XLWorkbook("test.xlsx");
// シート名_3を追加
var sheet3 = book.AddWorksheet("シート名_3");
// シート名_1とシート名_2の間にシート名_2を挿入
var sheet2 = book.AddWorksheet();
sheet2.Position = 2;
sheet2.Name = "シート名_2";
// シート名_4をシート名_1の前に挿入
var sheet4 = book.AddWorksheet("シート名_4", 1);
// シート名_4を削除
sheet4.Delete();
// ファイルを保存
book.Save();
セルに文字列を設定する
値を設定するにはworksheet.Cell(row, column).Valueで行います。
セルの指定をする場合にB3とかだとついつい.Cell(2, 3)とかやりたくなるのですが逆なので間違えないようにしましょう。
なお、.Valueでは数式は設定できません。仮に=B3としてもセルに”=B3″となるだけです。
XLWorkbook book = new XLWorkbook("test.xlsx");
// シートを選択
var sheet1_byNumber = book.Worksheet(1);
var sheet1_byName = book.Worksheet("シート名_1");
// B3のセルを選択
var cell_B3 = sheet1_byNumber.Cell(3, 2); // Cell(行数, カラム数)
cell_B3.Value = "ClosedXMLで値を書き込み";
// ファイルを保存
book.Save();
セルに数式を設定する
.Valueでは設定できない数式を.FormulaA1で設定します。
以下はセルB3を参照する数式をB5に設定している例です。
XLWorkbook book = new XLWorkbook("test.xlsx");
// 1シート目を選択
var sheet1_byNumber = book.Worksheet(1);
var cell_B5 = sheet1_byNumber.Cell(5, 2);
cell_B5.FormulaA1 = "B3";
// ファイルを保存
book.Save();
セルの値を取得する
値の設定時と同様に.Valueで値を取得できます。
B3にABC、B5に数式で=B3が設定されているとします。
以下の例ではb3_valueとb5_valueで取得される文字列は”ABC”が取得され、b5_formulaは”=B3″が取得されます。
XLWorkbook book = new XLWorkbook("test.xlsx");
// 1シート目を選択
IXLWorksheet sheet = book.Worksheet(1);
// B3の値を取得
var b3_value = sheet.Cell(3, 2).Value; // ABC
// B5の値を取得
var b5_value = sheet.Cell(5, 2).Value; // ABC
// 数式を取得
var b5_formula = sheet.Cell(5, 2).FormulaA1; // =B3
値を取得する際に、取得箇所が固定されていればそのまま指定すればいいですが、どこまで値が設定されているかわからないことがあると思います。
そういう場合は以下のように値が設定されている一番左上と右下のインデックスを取得できるのでこの値を利用してループさせることでセルの値を上手く取得できます。
例として画像のようなデータを使用します。
XLWorkbook book = new XLWorkbook("sample data.xlsx");
// 1シート目を選択
IXLWorksheet sheet = book.Worksheet(1);
// 右下のセル位置を取得(C12)
var lastCell = sheet.LastCellUsed();
var lastColumn = sheet.LastColumnUsed().ColumnNumber(); // 12
var lastRow = sheet.LastRowUsed().RowNumber(); // 3
// 欲しいデータはB3,C3~B12,C12のためループの開始位置は指定しておく
for (var row = 3; row <= lastRow; row++)
{
for (var column = 2; column <= lastColumn; column++)
{
Console.WriteLine($"column, row = {column}, {row} ({sheet.Cell(row, column).Value.ToString()})");
}
}
// 左上の位置を取得したい場合
var firstCell = sheet.FirstCellUsed();
var firstColumn = sheet.FirstColumnUsed().ColumnNumber(); // 2
var firstRow = sheet.FirstRowUsed().RowNumber(); // 2
以下が実行結果です。
column, row = 2, 3 (1)
column, row = 3, 3 (1000)
column, row = 2, 4 (2)
column, row = 3, 4 (2000)
column, row = 2, 5 (3)
column, row = 3, 5 (3000)
column, row = 2, 6 (4)
column, row = 3, 6 (4000)
column, row = 2, 7 (5)
column, row = 3, 7 (5000)
column, row = 2, 8 (6)
column, row = 3, 8 (6000)
column, row = 2, 9 (7)
column, row = 3, 9 (7000)
column, row = 2, 10 (8)
column, row = 3, 10 (8000)
column, row = 2, 11 (9)
column, row = 3, 11 (9000)
column, row = 2, 12 (10)
column, row = 3, 12 (10000)
コメント