SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

ClosedXMLでxlsxファイルの読み書きを行う

C#から、xlsx形式のエクセルファイルを簡単に操作できる、ClosedXMLというライブラリを使ってみました。

Office2007以降のドキュメント形式について

Office2007以降で使われている、xlsx/docx/pptxなどの形式のファイルは、OpenXMLというフォーマットで作成されています。

これらのファイルを読み込むために、OpenXML SDKというSDKがMSから提供されています。
https://msdn.microsoft.com/ja-jp/library/office/bb448854%28v=office.15%29.aspx
https://github.com/OfficeDev/Open-XML-SDK

ただし、このOpenXML SDKは使い方が結構面倒で、
「エクセルのシートをちょろっと読み書きしたい」というだけでも、だいぶ仰々しいコードになってしまいます。

ClosedXMLについて

ClosedXMLというライブラリは、このOpenXML SDKをラップして、シンプルにxlsxファイルを操作できるようにしてくれているライブラリです。
https://closedxml.codeplex.com/

参考リンク

↓のブログの一連の記事が、たくさんのサンプルと共にとても丁寧に説明されていて勉強になります!!
http://nineworks2.blog.fc2.com/?tag=ClosedXML&page=3


あとは↓のページのShowcaseを一通り見てみるとなんとなく使い方は掴めるかと。
https://closedxml.codeplex.com/wikipage?title=Showcase&referringTitle=Documentation

インストール

Nugetで「ClosedXML」で検索&インストールします。
f:id:minami_SC:20150621172003p:plain:w300


PMコンソールからインストールする場合は、以下のコマンド

Install-Package ClosedXML

使ってみる

まずは、HelloWorld的なコードを書いてみます。
↓のページをそのままやってみただけ。
https://closedxml.codeplex.com/wikipage?title=Hello%20World&referringTitle=Documentation

C#のコンソールアプリを作り、Main関数にたった4行書くだけでxlsx形式のエクセルシートが作れました。
f:id:minami_SC:20150621172024p:plain

Program.cs
using ClosedXML.Excel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClosedXMLTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var workbook = new XLWorkbook();
            var worksheet = workbook.Worksheets.Add("Sample Sheet");
            worksheet.Cell("A1").Value = "Hello World!!";
            workbook.SaveAs("HelloWorld.xlsx");
        }
    }
}

基本概念

まずは、概念や言葉の整理。
知ってる人には当たり前、という内容ですがとりあえず。
f:id:minami_SC:20150621174146p:plain:w300
まず、xlsx形式のファイル全体に対応する概念がブックです。
xlsxのファイルを読み込んだり作成したりすると、対応するブックのインスタンスが取得できます。

ブックには、複数のシートが含まれます。
シートは上記画像のように、エクセル内のシートに該当します。
そして、シート内には、たくさんのセルが行列に並んでいる、という構造になっています。

これらのブック/シート/セルという要素は、ClosedXMLを使ったプログラム中ではXLWorkbook/XLWorksheet/XLCellなどという名前のクラスとして出てきます。


使い方

一通りの説明は、以下のページのリンクから見れます。
https://closedxml.codeplex.com/documentation
とりあえず、自分がよく使いそうな操作をいろいろメモしときます。

ワークブックの操作

要は、エクセルのファイル作成とかにかかわるような操作

詳細はこの辺のドキュメント↓
https://closedxml.codeplex.com/wikipage?title=Workbook%20Properties&referringTitle=Documentation
https://closedxml.codeplex.com/wikipage?title=Loading%20and%20Modifying%20Files&referringTitle=Documentation

操作 メソッド
ブックの作成 var wb = new XLWorkbook()
ブックを開く var wb = new XLWorkbook(ファイルパス)
ブックの保存 wb.SaveAs("HelloWorld.xlsx");
ブックの上書き保存 wb.Save()

また、ワークブックの新規作成や、既存のxlsxファイルの読み込みは、XLWorkbookのインスタンス生成で行います。

            // ワークブックの作成
            var workbook1 = new XLWorkbook();

            // ファイルを指定して開く
            var workbook2 = new XLWorkbook("HelloWorld.xlsx");

            // ワークブックの保存
            workbook1.SaveAs("HelloWorld.xlsx");

ワークシートの操作

続いてワークシートに関する操作です。
ワークブックのWorksheetsプロパティのAddメソッドでシートの追加。
また、Worksheet()メソッドで特定のシートを指定して、シートの内容にアクセスできます。

            // ワークブックの作成
            var workbook = new XLWorkbook();

            // ワークブックにシートを追加
            var worksheet = workbook.Worksheets.Add("Sample Sheet");

            // ワークシートのコピー
            var wsSource = workbook.Worksheet(1);
            wsSource.CopyTo("Copy");
            wsSource.CopyTo("Copy2");

            // ワークシートの削除
            workbook.Worksheet(2).Delete();

            // ワークブックの保存
            workbook.SaveAs("HelloWorld.xlsx");

結果はこんな感じ
f:id:minami_SC:20150621172238p:plain


セルの操作

本題となる、セルの扱いについてです。

セルの情報を取得/設定

セルの情報を取得/設定するには、以下のようにCellメソッドに引数として、目的のセルの位置を渡してXLCellクラスのインスタンスを取得することで行います。

            // ワークブックの作成
            var workbook = new XLWorkbook();
            // ワークブックにシートを追加
            var worksheet = workbook.Worksheets.Add("Sample Sheet");

            // row/columnを数値で指定
            var cell = worksheet.Cell(1, 3);
            cell.Value = "Hello World";

            // アルファベットと数字の組み合わせで指定
            worksheet.Cell("B3").Value = "hogehoge";

            // ワークブックの保存
            workbook.SaveAs("HelloWorld.xlsx");

ここで注意すべき点ですが、セルの位置指定は(行, 列)という順番で指定します。
ですが、自分はついつい(x, y)という順番で座標を書きたくなってしまいます。
ここはグッとこらえて、Excelの文化に合わせた位置指定をしましょうw
(VBAなどに慣れてれば、この辺のセル位置指定方法はしっくりくるのではと思います。。。)
f:id:minami_SC:20150621172249p:plain


セルの結合

以下のように、Rangeで領域を選択してからMergeメソッドを呼ぶことで、セルの連結ができます。
表のタイトル作ったりするときに使えますね。

            // 連結したセルを作成(Rangeを文字列で指定)
            var range1 = worksheet.Range("B1:C1");
            range1.Merge();
            range1.Value = "連結したセル";

            // 連結したセルを作成(Rangeを数値で指定)
            var range2 = worksheet.Range(2, 2, 2, 3);
            range2.Merge();
            range2.Value = "hogehoge";

f:id:minami_SC:20150621172311p:plain

セルのサイズの自動調整

セルに設定された値の幅に応じて、行/列のサイズを自動調整することができます。

            // ワークシート中の全ての列幅を自動調整
            worksheet.Columns().AdjustToContents();

            // 2~6列目のカラムを、自動調整
            worksheet.Columns(2, 6).AdjustToContents();

            // ワークシート中の全ての行の高さを自動調整
            worksheet.Rows().AdjustToContents();

            // 2~6行目を自動調整
            worksheet.Rows(2, 6).AdjustToContents();

コレクション操作

C#のコレクションを一気に書き込むことができます。
以下のようにCellのValueに、コレクションのインスタンスを渡すと、コレクションの中身を一気に書き込むことができます。

            // 文字列のリストを作成
            var list = new List<string>();
            for (int i = 0; i < 20; i++ )
            {
                list.Add(string.Format("hoge{0}さん", i));
            }

            // コレクションを一気にセルに設定する
            var cell = worksheet.Cell(1, 2);
            cell.Value = list;

f:id:minami_SC:20150621172326p:plain

スタイルの設定

以下のように、CellオブジェクトのStyleプロパティをいじることで、文字の色やサイズ、その他もろもろをいじれます。

文字のスタイルなど
            // テキストのスタイル設定

            // 水平方向のレイアウト
            var cell = worksheet.Cell(1, 1);
            cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Left;
            cell.Value = "左寄せ";

            cell = cell.CellBelow();
            cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
            cell.Value = "中央寄せ";

            cell = cell.CellBelow();
            // 太字
            cell = cell.CellBelow();
            cell.Style.Font.Bold = true;
            cell.Value = "太字";
            // 文字色
            cell = cell.CellBelow();
            cell.Style.Font.FontColor = XLColor.Red;
            cell.Value = "色の設定";
            // フォントの設定
            cell = cell.CellBelow();
            cell.Style.Font.FontSize = 16;
            cell.Style.Font.FontName = "MS P明朝";
            cell.Value = "フォントの設定";

            // ワークシート中の全ての列幅を自動調整
            worksheet.Columns().AdjustToContents();

f:id:minami_SC:20150621172335p:plain

罫線の設定

罫線もスタイルとして指定を行います。
Borderプロパティに、○○Borderというプロパティが複数用意されているので、罫線を設定したい方向のプロパティに対して指定を行います。

            // セルに対して罫線を引く
            var cell = worksheet.Cell(1, 1);
            cell.Value = "hoge";
            cell.Style.Border.BottomBorder = XLBorderStyleValues.Thin;
            cell.Style.Border.BottomBorderColor = XLColor.Red;

            // Regionにセルを引く
            var range = worksheet.Range("B2:D4");
            range.Style.Border.OutsideBorder = XLBorderStyleValues.Thick;

f:id:minami_SC:20150621172342p:plain

塗りつぶしとか
            // 塗りつぶしの設定
            var cell1 = worksheet.Cell(2, 2);
            cell1.Style.Fill.BackgroundColor = XLColor.Red;

            // 塗りつぶしパターンの設定
            var cell2 = worksheet.Cell(4, 2);
            cell2.Style.Fill.PatternType = XLFillPatternValues.DarkGrid;
            cell2.Style.Fill.PatternColor = XLColor.Gray;
            cell2.Style.Fill.PatternBackgroundColor = XLColor.Blue;

f:id:minami_SC:20150621172350p:plain


メソッドチェーンでのスタイル指定

スタイルはメソッドチェーンで連結して、一気に設定することもできます。
プロパティ名の頭に「Set」という接頭辞を付けたメソッドがそれぞれ用意されていて、このメソッド呼び出しでは、以下のように複数のスタイル指定を続けて記述することができます。
スタイルのプロパティ設定は、結構長くなりがちなんで、こういうのを上手く使うと、簡潔なコードを書けそうです。

            var range = worksheet.Range("B2:C4");
            range.Style.Font.SetBold()
                       .Fill.SetBackgroundColor(XLColor.Red)
                       .Border.SetOutsideBorder(XLBorderStyleValues.Thick)
                       .Alignment.SetHorizontal(XLAlignmentHorizontalValues.Center);

            worksheet.Cell("B2").Value = "hoge";

f:id:minami_SC:20150621172359p:plain



基本的な使い方は、ざっとこんな感じ。
これはほんと、メッチャ便利!!