【C#】NPOIを使ってExcelファイルを作成・編集する

#はじめに
NPOIを触ってみたので、備忘録も兼ねて導入からExcelファイルの作成・編集までをまとめました。

# NPOIとは
Officeのドキュメントの操作を行う事が出来るApache POI(Javaライブラリ)の.NET用に移植されたライブラリです。C#やVB.netでOfficeのドキュメントを作成・編集する事が出来ます。また、Licenceは[Apache 2.0](http://choosealicense.com/licenses/apache-2.0/)です。
ここではxlsファイルやxlsxファイルといったExcelのドキュメントを扱う場合について記載します。

また、Apache POIに準拠しているため、Apache POIのサンプルを参考に出来ます。

POIの機能で主にExcelに関連があるのは下記の機能です。

- HSSF: Microsoft Excel(xls形式)(excel 97-2003)
- XSSF: Office Open XML Workbook形式(xlsx形式)(excel 2007以降)

参考：
https://ja.wikipedia.org/wiki/Apache_POI


# 動作環境
Visual Studio 2015 Community
.NET Framework 4.5.2
NPOI 2.2.1

# NPOIを使うには
NuGet(パッケージマネージャ)でインストール出来ます。
https://www.nuget.org/packages/NPOI/

`Install-Package NPOI`をパッケージマネージャのコンソール上で実行すればインストールされ、参照等も設定されます。パッケージマネージャはメニューから[ツール]⇒[NuGetパッケージマネージャー]⇒[パッケージマネージャーコンソール]で表示されます。

![npoi_install.gif](https://qiita-image-store.s3.amazonaws.com/0/86057/9ebdcab6-6049-d4c4-74ac-4ffb9ea364ac.gif)

# Excelファイルを作成する
ブックを作成し、作成したブックを保存する事でExcelファイルを作成する方法を紹介します。

##サンプルコード
拡張子に応じて対応するブックのインスタンスを作成した後、保存します。
また、シート無しのブックを保存すると保存後のExcelファイルを開いた時にエラーで開けなくなるので作成後に一つだけシートを追加しています。

```csharp
using System;
using System.IO;
using NPOI.SS.UserModel;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;

namespace Sample_NPOI
{
	class Program
	{
		static void Main( string[] args )
		{
			try {
				string filePath = "sample.xlsx";

				//ブック作成
				var book = CreateNewBook( filePath );

				//シート無しのexcelファイルは保存は出来るが、開くとエラーが発生する
				book.CreateSheet( "newSheet" );

				//ブックを保存
				using( var fs = new FileStream( filePath, FileMode.Create ) ) {
					book.Write( fs );
				}
			}
			catch( Exception ex ) {
				Console.WriteLine( ex );
			}
		}

		//ブック作成
		static IWorkbook CreateNewBook( string filePath )
		{
			IWorkbook book;
			var extension = Path.GetExtension( filePath );

			// HSSF => Microsoft Excel(xls形式)(excel 97-2003)
			// XSSF => Office Open XML Workbook形式(xlsx形式)(excel 2007以降)
			if( extension == ".xls" ) {
				book = new HSSFWorkbook();
			}
			else if( extension == ".xlsx" ) {
				book = new XSSFWorkbook();
			}
			else {
				throw new ApplicationException( "CreateNewBook: invalid extension" );
			}

			return book;
		}
	}
}
```

サンプルコードを実行すると以下のようなExcelファイルが作成されます。

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/86057/188eb36c-af76-9423-8266-44bf1d35f7b3.png)


## 解説
サンプルコードの簡略な解説です。

### ブックを作成
xlsファイルならばHSSFWorkbookクラス、xlsxファイルならばXSSFWorkbookクラスのインスタンスを作成する事でブックを作成できます。どちらのクラスもIWorkbookインタフェースを継承しています。

### Excelファイルを保存
IWorkbookインタフェースのWriteメソッドを作成したFileStreamクラスのインスタンスを渡す事でExcelファイルを保存出来ます(FileStreamのコンストラクタには保存先のパスを指定)。

# Excelファイルを編集する
シートのセルに値を設定する方法を紹介します。
また、併せてファイル読み込み等も紹介します。

##サンプルコード
先程作成したExcelファイルを読み込んでシートのセルに設定します。

```csharp
using System;
using System.IO;
using NPOI.SS.UserModel;

namespace Sample_NPOI
{
	class Program
	{
		static void Main( string[] args )
		{
			try {
				//ブック読み込み
				var book = WorkbookFactory.Create( "sample.xlsx" );

				//シート名からシート取得
				var sheet = book.GetSheet( "newSheet" );

				//セルに設定
				WriteCell( sheet, 0, 0, "0-0" );
				WriteCell( sheet, 1, 1, "1-1" );
				WriteCell( sheet, 0, 3, 100 );
				WriteCell( sheet, 0, 4, DateTime.Today );

				//日付表示するために書式変更
				var style = book.CreateCellStyle();
				style.DataFormat = book.CreateDataFormat().GetFormat( "yyyy/mm/dd" );
				WriteStyle( sheet, 0, 4, style );

				//ブックを保存
				using( var fs = new FileStream( "sample2.xlsx", FileMode.Create ) ) {
					book.Write( fs );
				}
			}
			catch( Exception ex ) {
				Console.WriteLine( ex );
			}
		}

		//セル設定(文字列用)
		public static void WriteCell( ISheet sheet, int columnIndex, int rowIndex, string value )
		{
			var row = sheet.GetRow( rowIndex ) ?? sheet.CreateRow( rowIndex );
			var cell = row.GetCell( columnIndex ) ?? row.CreateCell( columnIndex );

			cell.SetCellValue( value );
		}

		//セル設定(数値用)
		public static void WriteCell( ISheet sheet, int columnIndex, int rowIndex, double value )
		{
			var row = sheet.GetRow( rowIndex ) ?? sheet.CreateRow( rowIndex );
			var cell = row.GetCell( columnIndex ) ?? row.CreateCell( columnIndex );

			cell.SetCellValue( value );
		}

		//セル設定(日付用)
		public static void WriteCell( ISheet sheet, int columnIndex, int rowIndex, DateTime value )
		{
			var row = sheet.GetRow( rowIndex ) ?? sheet.CreateRow( rowIndex );
			var cell = row.GetCell( columnIndex ) ?? row.CreateCell( columnIndex );

			cell.SetCellValue( value );
		}

		//書式変更
		public static void WriteStyle( ISheet sheet, int columnIndex, int rowIndex, ICellStyle style )
		{
			var row = sheet.GetRow( rowIndex ) ?? sheet.CreateRow( rowIndex );
			var cell = row.GetCell( columnIndex ) ?? row.CreateCell( columnIndex );

			cell.CellStyle = style;
		}
	}
}
```

サンプルコードを実行すると以下のようなExcelファイルが作成されます。
(日付表示のため、列の幅を広げています。)

![sample2.png](https://qiita-image-store.s3.amazonaws.com/0/86057/8cad6b7a-a116-e86a-aafd-d9b4ff28fb5f.png)

## 解説
サンプルコードの簡略な解説です。

### Excelファイルを開く
WorkbookFactory.Createの引数にファイルパスを渡して呼び出すだけで指定したファイルパスのExcelファイルを開いて、ファイルパスに応じた形式(HSSF・XSSF)のブックを取得出来ます。

### セルの取得
セルに書き込むためにはまず、セルを取得する必要があります。

シートから行のインスタンス、行からセルのインスタンスを取得する事が出来ます。また、それぞれ0オリジンとなっています。

ただし、設定されていない箇所を取得する場合、行取得時及びセル取得時にnullが取得されます。そのため、null取得時に取得対象を作成する必要があります。

### セルに書き込み
取得したセルのインスタンスの値を設定するメソッド(SetCellValue)を呼び出す事で設定します。設定する値(SetCellValueの引数)に対応した表示形式(文字列・数値・日付など)でセルに保存されます。

### 表示形式の変更
セルに書き込んでも表示形式までは変更されないのでデフォルト(標準)のままとなっています。そのため、日付の表示が数値表示となってしまいます。

そこで表示形式を変更する必要があります。
ただし、書式はブックが保持しているものなので注意する必要があります。セルから取得した書式だけ変えると意図しない挙動になります。
(HSSFの場合は全セルに反映されて、XSSFの場合は反映自体されませんでした。)

参考:
http://www.coppermine.jp/docs/programming/2011/11/apache-poi.html
http://irof.hateblo.jp/entry/20100313/p1


#おわりに
思ったより長くなりましたがNPOIの導入からExcelファイルの作成・編集までを記載しました。
最後に上述以外で世話になった参考URLを記載します。流石に数年前のサンプルコードだと現在のNPOIのバージョンでは動作しないので気を付けてください。

http://blog.okazuki.jp/entry/20091128/1259405232
http://www.javadrive.jp/poi/

https://github.com/tonyqus/npoi
(NPOIのGithubリポジトリ。Exampleディレクトリ内に使用例があり、参考になりました。)