c# でExcel のデータを取得するには？


**VisualStudio2019 環境です。**
**初心者なため、わからないこと、足りないことがあるかもしれません。**
**自己責任でお願いします。**
**まとめメモ**

今回はC#でExcelのデータを取得する方法を書いていこうと思います。
2つの方法がありますので、順番に紹介します。

# Excelにアクセスする方法

## １つ目の方法
Microsoft Access データベース エンジン 2010 再頒布可能コンポーネント
https://www.microsoft.com/ja-jp/download/details.aspx?id=13255
を使った方法です。
こちらの方法では、SQLを使用してデータを取得できます。

## ２つ目の方法
COMオブジェクトの
「Micorosoft Excel xxx Object Library」
を使用する方法です。

- - -

# １つ目の方法から説明していきます。
## 前提
Microsoft Access データベース エンジン 2010 再頒布可能コンポーネントのダウンロードをしてください。

## 必要なusing
- １つ目
using System.Data.Common;
クラス　DbDataReader、DbCommand を使用するために必要。

- ２つ目
using System.Data.OleDb;
クラス　OleDbConnection　を使用するために必要。

- ３つ目
using System.Data;
クラス　DataTable　を使用するために必要。

## コード例を書いてきます。

```ruby:qiita.rb
/ファイルディレクトリ "\"C:\\Users\\Book1.xlsx\"";/
/*** 宣言 ***/
DataTable Dt = new System.Data.DataTable();
OleDbConnection conn = new OleDbConnection();
DbDataReader oleReader;
DbCommand command = conn.CreateCommand();
string path2 = "\"C:\\\Users\\\Book1.xlsx\"";

/*** excelデータベース開く ***/
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path2 + "Extended Properties = \"Excel 12.0 Xml;HDR=YES;IMEX=1\"";
conn.Open();

/*** SQL SELECT文 設定 ***/
//シート１用　
command.CommandText = "SELECT " + 列名 + " FROM [Sheet1$] "+ 条件式 +" ;";

/*** SQL 実行 ***/
oleReader = command.ExecuteReader();
Dt.Load(oleReader);

/*** excelデータベース閉じる ***/
conn.Close();

```

## このコードの流れと説明をしていきます。
### 流れ
１ 宣言
２ excelデータベース開く
３ SQL SELECT文 設定
４ SQL 実行
５ excelデータベース閉じる


### コードの説明

- 1 宣言
DataTable Dt = new System.Data.DataTable();　は値をDtに取得します。
OleDbConnection conn = new OleDbConnection(); はExcelを開く、閉じる、
また、開く条件やExcelの場所などを設定する。
DbDataReader oleReader;　はSQLを実行するのに必要。
DbCommand command = conn.CreateCommand();　はSQL文を設定する。
string path2 = "\"C:\\Users\\Book1.xlsx\""; はExcelファイルのパスです。

- 2 excelデータベース開く
conn.ConnectionString =
"Provider = Microsoft.ACE.OLEDB.12.0;
 [  Microsoft.ACE.OLEDB.12.0;、
   Excel2002/2003で作成したブックに接続する場合は、Microsoft.Jet.OLEDB.4.0; を指定します。 ]

  Data Source=" + path2 + 
 [ Excelファイルのパスです。]

   Extended Properties =
  \+  "\"Excel 12.0 Xml;HDR=YES;IMEX=1\"";
 [ Excel の 拡張子
   xls	Excel 8.0
   xlsx	Excel 12.0 Xml
   xlsb	Excel 12.0
   xlsm	Excel 12.0 Macro ]
 [ HDR = YES;　は列の先頭セルの名前の定義で定義された名前。
   No を指定した場合、フィールド名は、F1、F2、F3 のように F[列番号] ]
 [ IMEX=1 テキストとして値を取得　だと思います、よくわかってない。]

  conn.Open(); は開く

- ３SQL SELECT文 設定 は
command.CommandText にSQLを設定しています。　FROMにはシート名と設定

- ４SQL 実行　は
Dt.Load(oleReader);　でDtに値を取得します。

- ５excelデータベース閉じる　は
conn.Close();　は閉じる

### 以上が一つ目の方法です。

- - -

# ２つ目の方法を説明していきます。

## 前提
ソリューション　エクスプローラーの参照を右クリック
参照を追加で
COMオブジェクトの「Micorosoft Excel xxx Object Library」を追加します。

## 必要なusing

- １つ目
using Microsoft.Office.Interop.Excel;
クラス　Application、Workbook、Worksheet、Range を使用するために必要。

- ２つ目
using System.Runtime.InteropServices;
クラス　Marshal　を使用するために必要。


## コード例を書いてきます。

```ruby:qiita.rb
// ファイルディレクトリ "\"C:\Users\Book1.xlsx\"";
/*** 宣言 ***/
string str;
Application _application = null;
_application = new Application();
Workbook _workbook = null;
Worksheet _worksheet = null;
string path2 = "\"C:\\Users\\Book1.xlsx\"";

/*** Book1.xlsx ファイルのパスを設定　開く ***/
_workbook = _application.Workbooks.Open(path2, false);

/*** シートを設定 ***/
_worksheet = _workbook.Worksheets[Sheet1];

/*** セルを指定 ***/
var cells = _worksheet.Cells;
var range1 = cells[Excelの縦, Excelの横] as Range;

/*** セルのデータ取得 ***/
str = range1.Text.ToString();

/*** 解放 ***/
Marshal.ReleaseComObject(range1);
Marshal.ReleaseComObject(cells);
_workbook.Close();
_application.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(_workbook);            System.Runtime.InteropServices.Marshal.ReleaseComObject(_application);

```

**このコードの流れと説明をしていきます。**
１宣言
２Book1.xlsx ファイルのパスを設定　開く
３シートを設定
４セルを指定
５セルのデータ取得 
６解放


## コードの説明

- １宣言

```ruby:qiita.rb
string str;  /は値を取得します。/
_application = new Application();  /はExcelを開く、閉じる、
また、開く条件やExcelの場所などを設定する。/
Workbook _workbook = null;  /はワークブック/
Worksheet _worksheet = null;  /はシート/
string path2 = "\"C:\\Users\\Book1.xlsx\"";  /はExcelファイルのパスです。/
```

- ２Book1.xlsx ファイルのパスを設定　開く

```ruby:qiita.rb
_workbook = _application.Workbooks.Open(path2, false); 
/はExcelファイルのパス,
読み取り専用で開く場合はTrueを指定します。省略時はFalse扱いになります。
falseは　書き込みモードのため、本来は省略でよいはずなのですが、エラーになる？/
```

  詳しくは　ほかの人のこのサイトの参照をお勧めします。
  Excel作業をVBAで効率化
  https://vbabeginner.net/how-to-open-workbook/


- ３シートを設定

```ruby:qiita.rb
_worksheet = _workbook.Worksheets[Sheet1]; /はシートを設定/
```

- ４セルを指定

```ruby:qiita.rb
var cells = _worksheet.Cells; /はセルの値を抜きだし /
var range1 = cells[Excelの縦, Excelの横] as Range; /はExcelの縦, Excelの横の位置の値を所得/
```
- ５セルのデータ取得 

```ruby:qiita.rb
str = range1.Text.ToString();
```

- ６解放
全て解放

```ruby:qiita.rb
Marshal.ReleaseComObject(range1);
Marshal.ReleaseComObject(cells);
_workbook.Close();
_application.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(_workbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(_application);
```
---

# 備考

## 1 エラーが起きる
プログラム作成時やテスト時に途中終了すると、Excelが開いたままになることも、
　その時はタスクマネージャーから終了しよう。



 ## 2 動作が遅い
 ２つ目の方法の,
COMオブジェクトの「Micorosoft Excel xxx Object Library」は
処理に時間がかかることがある？

## 3 Excelのファイルパスの取得を自動化
**resourcesファイルにExcelファイルを追加した後**

- １宣言の
```ruby:qiita.rb
string path2 = "\"C:\\Users\\Book1.xlsx\"";  /はExcelファイルのパスです。/
```
を下のコードに置き換える

```ruby:qiita.rb
using System.Reflection;

Assembly myAssembly = Assembly.GetEntryAssembly();
string path = myAssembly.Location;
/ 下3行　@"\\" の\は 一個でよい/
var path2 = path.Substring(0, path.LastIndexOf(@"\\"));  /後ろから\まで消去/
path = path2.Substring(0, path2.LastIndexOf(@"\\"));     
path2 = path.Substring(0, path.LastIndexOf(@"\\") + 1);
path2 = path2 + "resources\\Book1.xlsx";

```

## 4 データをセットする方法(２つ目のプログラムのみ)

- ５セルのデータ取得

```ruby:qiita.rb
/*** セルのデータ取得 ***/
str = range1.Text.ToString();
```
を下のコードに置き換える

```ruby:qiita.rb
/*** 値を設定 ***/
range1.Value = "テキスト";
_workbook.Save();
```