あたも技術ブログ

セットジャパンコーポレーションの社員が運営しています。

【C#】Excelの取り扱いにClosedXMLを使用する

 今回はC#Excelを使用したい場合を考えたいと思います。2008年辺りまではCOMコンポーネントを使用してMicrosoft Excel 12.0 Object Libraryを参照し、COMオブジェクトの解放地獄でかなり苦しんでおられたのではないでしょうか。
 Office2007以降の場合、xlsx、xlsmファイルとなり内部的にはXML形式となりました。これによってCOMオブジェクトうを使用せずにExcelファイルを扱えるライブラリが色々公開されています。
 その中でClosedXMLをご紹介したいと思います。
 
1. Excelを扱うプロジェクトを作成します。
2. Visual Studioを起動し、「ツール」→「NuGet パッケージマネージャー」→「ソリューションの NuGet パッケージの管理」を選択します。
f:id:atamo_dev:20170719212412j:plain
3.「NuGet パッケージ管理ウィンドウ」で左のオンラインを選択します。
4. 右上オンラインの検索欄に「OpenXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212439j:plain
5. 表示された「DocumentFormat.OpenXml」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。
6. 右上オンラインの検索欄に「ClosedXML」と入力し、検索を実行します。
f:id:atamo_dev:20170719212451j:plain
7. 表示された「ClosedXML」を選択すると「インストール」ボタンが表示されていますので、「インストール」ボタンを押下し、指示に従ってインストールを行います。

 これで前準備は完了しました。

github.comOpenXML SDK
github.comClosedXML


 以下Excelを扱ったサンプルクラスです。

using ClosedXML.Excel;
using System;
using System.IO;

namespace ExcelSample
{
  /// <summary>
  /// Excelの読み込みとワークシート、セルへのアクセスを行うクラス
  /// </summary>
  public class ExcelLoader : IDisposable
  {
    #region メンバ変数
    /// <summary>
    /// Excelのワークブック(2013以降のExcelを指定すること)
    /// </summary>
    private XLWorkbook _Workbook = null;
    #endregion

    #region プロパティ
    /// <summary>
    /// 全てのワークシートを取得します。
    /// </summary>
    public IXLWorksheets Worksheets
    {
      get
      {
        if (this._Workbook != null)
        {
          return this._Workbook.Worksheets;
        }
        else
        {
          return null;
        }
      }
    }
    #endregion

    #region コンストラクタ
    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    public ExcelLoader()
    {
    }

    /// <summary>
    /// 新しいクラスのインスタンスを作成します。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    public ExcelLoader(string path)
    {
      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
      }
    }
    #endregion

    #region 公開メソッド
    /// <summary>
    /// 解放処理
    /// </summary>
    public void Dispose()
    {
      CloseExcel();
    }

    /// <summary>
    /// 引数で指定されたExcelファイルを開きます。
    /// </summary>
    /// <param name="path">Excelファイルのパス</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public bool OpenExcel(string path)
    {
      CloseExcel();

      if (!string.IsNullOrEmpty(path) && File.Exists(path))
      {
        // ファイルパスが設定されているかつ、そのパスのファイルが存在する場合、ファイルを開く
        this._Workbook = new XLWorkbook(path);
        return true;
      }
      else
      {
        return false;
      }
    }

    /// <summary>
    /// 指定したインデックスのワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="index">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, int index = 1)
    {
      if (this._Workbook == null)
      {
        return string.Empty;
      }

      try
      {
        var worksheet = this._Workbook.Worksheet(index);
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 指定したワークシートの指定セルを読み込みます。
    /// </summary>
    /// <param name="row">行番号</param>
    /// <param name="col">列番号</param>
    /// <param name="worksheet">ワークシートのインデックス番号</param>
    /// <returns>true:オープン成功、false:オープン失敗</returns>
    public string ReadCell(int row, int col, IXLWorksheet worksheet)
    {
      if (worksheet == null)
      {
        return string.Empty;
      }

      try
      {
        var cell = worksheet.Cell(row, col);
        return cell.Value as String;
      }
      catch
      {
        // 指定されたワークシートのセルが存在しなかった場合、空値を返却する
        return string.Empty;
      }
    }

    /// <summary>
    /// 現在オープンされているExcelファイルをクローズします。
    /// </summary>
    public void CloseExcel()
    {
      if (this._Workbook != null)
      {
        // 既にExcelが開かれている場合、破棄する
        this._Workbook.Dispose();
        this._Workbook = null;
      }
    }
    #endregion
  }
}

 クラスインスタンス生成時にExcelファイルのパスを指定し、Excelファイルからセルの読み込みを行う簡単なメソッドを実装したクラスです。
 COMオブジェクトの時代では速度面で遅く厳しいものがありましたが、ClosedXMLを使用した場合、速度もかなり速く利用を検討すべきだと思います。