C# プログラムでエクセルシートを読み込むサンプル

エクセル VBA は単体でいろいろな処理ができてとても便利ですが、より複雑な処理をしたいときには物足りなく感じることもあります。そこで C# プログラムからエクセルシートを読み込むサンプルプログラムを紹介します。

# 準備

VisualStudio で C# のプロジェクトを作成します。この例では ExcelLoader というコンソールアプリケーションプロジェクトを使用します。

## 参照の追加

下図のように [ソリューションエクスプローラ] => [参照の追加] を選択します。

![2015-10-23_00h07_55.png](https://qiita-image-store.s3.amazonaws.com/0/14284/4ef719c6-cc3d-2c8d-b689-268bbb9c2b0c.png)

ポップアップダイアログが表示されますので、左のリストで [COM] を選択し、右上のエディットボックスに "excel" 入力します。すると "Microsoft Excel [***] Object Library" が表示されますので、チェックを入れて [OK] ボタンを押します。

![2015-10-23_00h08_51.png](https://qiita-image-store.s3.amazonaws.com/0/14284/74d5ad32-696b-b845-310e-37bc53df43a3.png)

以上で準備は完了です。

# コード

そんなに長くないのでコードを丸ごと載せます。
`ExcelSheetReader` クラスの中がエクセルシートを読み込む処理で、 `Program` クラスの中が `ExcelSheetReader` の使用例です。使用例と言っても `Read` 関数を呼ぶだけですが。

```csharp:Program.cs
using System.Collections;
using System.Runtime.InteropServices;

namespace ExcelLoader
{
	class ExcelSheetReader
	{
		/// <summary>
		/// エクセルファイルの指定したシートを2次元配列に読み込む.
		/// </summary>
		/// <param name="filePath">エクセルファイルのパス</param>
		/// <param name="sheetIndex">シートの番号 (1, 2, 3, ...)</param>
		/// <param name="startRow">最初の行 (>= 1)</param>
		/// <param name="startColmn">最初の列 (>= 1)</param>
		/// <param name="lastRow">最後の行</param>
		/// <param name="lastColmn">最後の列</param>
		/// <returns>シート情報を格納した2次元文字配列. ただしファイル読み込みに失敗したときには null.</returns>
		public ArrayList Read(string filePath, int sheetIndex,
							  int startRow, int startColmn,
							  int lastRow, int lastColmn)
		{
			// ワークブックを開く
			if(!Open(filePath)) { return null; }

			Microsoft.Office.Interop.Excel.Worksheet sheet = mWorkBook.Sheets[sheetIndex];
			sheet.Select();

			var arrOut = new ArrayList();
			
			for(int r = startRow; r <= lastRow; r++)
			{
				// 一行読み込む
				var row = new ArrayList();
				for(int c = startColmn; c <= lastColmn; c++)
				{
					var cell = sheet.Cells[r, c];

					if (cell == null || cell.Value == null) { row.Add(""); }

					row.Add(cell.Value);
				}

				arrOut.Add(row);
			}

			// ワークシートを閉じる
			Marshal.ReleaseComObject(sheet);
			sheet = null;

			// ワークブックとエクセルのプロセスを閉じる
			Close();

			return arrOut;
		}


		/// <summary>
		/// 指定されたパスのエクセルワークブックを開く
		/// </summary>
		/// <param name="filePath">エクセルワークブックのパス(相対パスでも絶対パスでもOK)</param>
		/// <returns>エクセルワークブックのオープンに成功したら true. それ以外 false.</returns>
		protected bool Open(string filePath)
		{
			if (!System.IO.File.Exists(filePath))
			{
				return false;
			}

			try {
				mApp = new Microsoft.Office.Interop.Excel.Application();
				mApp.Visible = false;

				// filePath が相対パスのとき例外が発生するので fullPath に変換
				string fullPath = System.IO.Path.GetFullPath(filePath);
				mWorkBook = mApp.Workbooks.Open(fullPath);
			}
			catch
			{
				Close();
				return false;
			}

			return true;
		}

		/// <summary>
		/// 開いているワークブックとエクセルのプロセスを閉じる.
		/// </summary>
		protected void Close()
		{
			if (mWorkBook != null)
			{
				mWorkBook.Close();
				Marshal.ReleaseComObject(mWorkBook);
				mWorkBook = null;
            }

			if (mApp != null)
			{
				mApp.Quit();
				Marshal.ReleaseComObject(mApp);
				mApp = null;
            }
		}

		~ExcelSheetReader()
		{
			Close();
		}

		protected Microsoft.Office.Interop.Excel.Application mApp = null;
		protected Microsoft.Office.Interop.Excel.Workbook mWorkBook = null;
	}

	class Program
	{
		static void Main(string[] args)
		{
			var reader = new ExcelSheetReader();

			// 'sample.xlsx' の1番シートの 1A から 6C までを読む
			var sheet = reader.Read(@"sample.xlsx", 1, 1, 1, 6, 3);

			// コンソールに出力
			foreach(ArrayList row in sheet)
			{
				string s = "";
				foreach (var cell in row) { s += cell + ", "; }
				System.Console.WriteLine(s);
			}
		}
	}
}
```

*=== sample.xlsx ===*
![2015-10-23_00h16_34.png](https://qiita-image-store.s3.amazonaws.com/0/14284/c71025ff-4908-32c8-2397-fd6c168d744e.png)

### プログラム実行結果

```txt:console
品番, 名前, 価格,
1, りんご, 500,
2, みかん, 400,
3, 栗, 700,
4, ぶどう, 1200,
5, 桃, 2000,
続行するには何かキーを押してください . . .
```

# 変更履歴

2015/10/23 コメント欄のご指摘を参考にオブジェクトの解放処理とコメントを追加しました。