OpenXMLでExcelファイルを操作しよう (1) - Excelファイルを新規作成したい

## はじめに

先月(2021/08)、技術評論社より『[C#コードレシピ集](https://www.amazon.co.jp/dp/4297122650)』を出版しました。
この本には、385のコードレシピが掲載されています。執筆している段階では385を超えるレシピを予定していたのですが、ページ数の関係（この本700ページを超える分厚い本です）でいくつかのレシピは没にしています。
その中にOpen XMLを使ってExcelを操作するものがあります。そのまま眠らせてしまうのは残念なので、Qiitaでこのレシピを5回に分けて紹介したいと思います。

1. [OpenXMLでExcelファイルを操作しよう (1) - Excelファイルを新規作成したい](https://qiita.com/gushwell/items/5c689e86014105313017)  ← 今ここ
1. [OpenXMLでExcelファイルを操作しよう (2) - セルに値を設定したい](https://qiita.com/gushwell/items/66ef40e9fedf8e0b6237)
1. [OpenXMLでExcelファイルを操作しよう (3) - セルの値を読み込みたい](https://qiita.com/gushwell/items/d719fd287be1b4815f2f)
1. [OpenXMLでExcelファイルを操作しよう (4) - 全てのセルの値を取得したい](https://qiita.com/gushwell/items/456e9da791f1a8d5bb59)
1. [OpenXMLでExcelファイルを操作しよう (5) - セルに書式を設定したい](https://qiita.com/gushwell/items/51c90012e724088d318c)

コードレシピの環境は、C#9.0 + .NET 5 のコンソールアプリケーションです。

なお、『[C#コードレシピ集](https://www.amazon.co.jp/dp/4297122650)』では、NPOIを使ってエクセルファイルを操作するレシピを掲載しています。


## 準備

C#でExcelファイルを操作する方法はいくつか存在しますが、ここでは、[OpenXML SDK](https://github.com/OfficeDev/Open-XML-SDK)を利用した方法を紹介したいと思います。
OpenXML SDKを使えばExcelがインストールされていないPCからもExcel文書を作成することが可能です。

OpenXML SDKを利用するには、Visual Studioの「NuGet パッケージの管理」を利用してDocumentFormat.OpenXmlパッケージをインストールします。あるいは、以下のコマンドでプロジェクトにパッケージをインストールします。ここでは、バージョン2.13.1を利用しています。

```
dotnet add package DocumentFormat.OpenXml --version 2.13.1
```

## 名前空間

OpenXML SDKを利用する際に必要な名前空間を以下に示します。

```cs
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Packaging;
```

## サンプルコードの方針

ここでは、MyExcelBookクラスを定義し、そこにエクセルファイルを操作するメソッドを追加していきます。そうすることで、OpenXMLが提供する機能をより理解しやすくなると思います。

## 定義するメソッド

以下のメソッドを定義します。OpenXMLの機能をカプセル化により抽象度をあげています。

メソッド        | 機能
----------------|---------------------
CreateBook  | エクセルのBookを作成する　（静的メソッド）
CreateSheet  | Bookにシートを追加する
Save | 作成したBookを保存する

# MyExcelBookクラス

上記3つのメソッドを定義したMyExcelBookクラスを以下に示します。ここで示したコードが、Excelファイルを操作する出発点となります。第２回目以降は、このMyExcelBookクラスに機能を追加していくことになります。

具体的にOpenXMLのどんな機能を使っているのかはコメントを読んでください。

```cs
sealed class MyExcelBook : IDisposable {
    private MyExcelBook() { }

    public void Dispose() => _document?.Dispose();

    private SpreadsheetDocument _document;
    private WorkbookPart _workbookpart;
    private WorksheetPart _worksheetPart;
    private Sheets _sheets;

    public static MyExcelBook CreateBook(string filepath) {
        var book = new MyExcelBook();
        // Excelのドキュメントを新規に作成する
        book._document = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook);

        // ドキュメントにワークブックを追加する
        book._workbookpart = book._document.AddWorkbookPart();
        book._workbookpart.Workbook = new Workbook();

        // ワークブックにシートの入れ物を追加する
        book._sheets = book._workbookpart.Workbook.AppendChild<Sheets>(new Sheets());
        return book;
    }

    // シートを作成する
    public void CreateSheet(string sheetname) {
        // シート作成のための準備
        _worksheetPart = _workbookpart.AddNewPart<WorksheetPart>();
        _worksheetPart.Worksheet = new Worksheet(new SheetData());

        // シートを作成し追加する
        var max = (uint)(_sheets.Count() + 1);
        var sheet = new Sheet {
            Id = _workbookpart.GetIdOfPart(_worksheetPart),
            SheetId = max,
            Name = sheetname
        };
        _sheets.Append(sheet);
    }
    
    // 保存する
    public void Save() {
        _workbookpart.Workbook.Save();
        _document.Close();
    }
}
```


## MyExcelBookクラスを使って、エクセルファイルを新規作成する

それでは、MyExcelBookクラスを利用したコードを示しましょう。ここでは新規にExcelファイルを作成し、空のシートを挿入しています。
OpenXMLのAPIをダラダラと羅列すると何をやっているのかわからないコードになりがちですが、こうすれば、何をやっているのかがとてもよくわかります。


```cs
using var book = MyExcelBook.CreateBook("example.xlsx");
book.CreateSheet("sheet1");
book.CreateSheet("sheet2");
book.Save();
```

以下のようなExcelファイルが作成されます。

![スクリーンショット 2020-11-25 20.31.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29415/9c532b70-adda-8e9d-b6ee-4a8d0b52ba6a.png)