.NETとC#でストリームを使ったExcel操作

.NET開発において、**バイトストリームを利用してExcelファイルを動的に操作する方法**は、データ処理において効率的かつ柔軟な手段を提供します。この方法により、開発者はメモリ内で直接Excel文書を作成、編集、保存でき、ファイルの直接保存や読み取りを必要としないため、アプリケーションのパフォーマンスと安全性が向上します。ストリーム技術を利用したExcel操作は、データ処理プロセスを簡素化するだけでなく、並列処理や一時データ管理をサポートするため、多様なデータ処理要件に対応できます。本記事では、**.NETプラットフォームでC#を使用して、バイトストリームを介してExcelファイルを作成、読み取り、編集、および保存する方法**を紹介します。

- **[C#でExcelをバイトストリームとして作成・保存](#cでexcelをバイトストリームとして作成保存)**
- **[C#でバイトストリームからExcelを読み取る](#cでバイトストリームからexcelを読み取る)**
- **[C#でバイトストリームを介してExcelを編集](#cでバイトストリームを介してexcelを編集)**

本記事で使用する方法は、無料で利用できる[Free Spire.XLS for .NET](https://jp.e-iceblue.com/introduce/free-spire-xls-for-net.html)を必要とします。NuGetコマンド：`Install-Package FreeSpire.XLS`。

## C#でExcelをバイトストリームとして作成・保存

`Workbook`インスタンスを作成することでExcelワークブックを直接作成し、データを追加したりフォーマットを設定したりした後、`Workbook.SaveToStream()`メソッドを使用してバイトストリームとして保存できます。新しいExcelワークブックにはデフォルトで3つのワークシートが含まれています。以下はその手順の例です：

1. `Workbook`インスタンスを作成します。
2. `Workbook.Worksheets[]`プロパティを使用してワークブックにアクセスします。
3. `DataTable`を利用して表形式のデータを定義または読み取ります。
4. `Workbook.InsertDataTable()`メソッドを使用してデータをワークシートに挿入するか、`Worksheet.Range[].Value`プロパティを使用してセルに直接データを追加します。
5. `CellRange.Style`プロパティを利用してセルのフォーマットを設定します。
6. `Worksheet.AutoFitColumn()`メソッドを使用して列幅を自動調整します。
7. `Workbook.SaveToStream()`メソッドを使用してExcelワークブックを新規または既存のバイトストリームに保存します。

**コード例**
```csharp
using Spire.Xls;
using System.Data;
using System.Drawing;

namespace CreateExcelStream
{
    class Program
    {
        static void Main(string[] args)
        {
            // 新しいワークブックのインスタンスを作成
            Workbook workbook = new Workbook();

            // ワークブックの最初のワークシートを取得
            Worksheet sheet = workbook.Worksheets[0];

            // サンプルデータを含むDataTableを作成してデータを追加
            DataTable table = new DataTable("従業員情報");
            table.Columns.Add("ID", typeof(int));
            table.Columns.Add("名前", typeof(string));
            table.Columns.Add("性別", typeof(string));
            table.Columns.Add("職位", typeof(string));
            table.Columns.Add("部署", typeof(string));
            table.Columns.Add("給与", typeof(decimal));
            table.Columns.Add("入社日", typeof(DateTime));
            // 行を追加（日本語データを含む内容でテーブルを埋める）
            table.Rows.Add(1, "佐藤和也", "男", "ソフトウェアエンジニア", "開発部", 750000, DateTime.Parse("2020-03-15"));
            table.Rows.Add(2, "鈴木美咲", "女", "プロジェクトマネージャー", "プロジェクト管理室", 850000, DateTime.Parse("2019-06-22"));
            table.Rows.Add(3, "田中康介", "男", "システムアナリスト", "情報技術部", 800000, DateTime.Parse("2018-07-11"));
            table.Rows.Add(4, "高橋彩香", "女", "UXデザイナー", "デザイン部", 700000, DateTime.Parse("2021-04-05"));
            table.Rows.Add(5, "山本健太", "男", "営業担当", "営業部", 650000, DateTime.Parse("2020-09-10"));
            table.Rows.Add(6, "伊藤真理子", "女", "会計士", "財務部", 720000, DateTime.Parse("2017-11-28"));
            table.Rows.Add(7, "渡辺浩二", "男", "人事マネージャー", "人事部", 820000, DateTime.Parse("2016-05-18"));
            table.Rows.Add(8, "中村菜々子", "女", "法務顧問", "法務部", 900000, DateTime.Parse("2015-02-14"));
            table.Rows.Add(9, "小林翔", "男", "CEO", "最高経営陣", 1200000, DateTime.Parse("2014-08-01"));

            // DataTableのデータをワークシートに挿入
            sheet.InsertDataTable(table, true, 1, 1);

            // ワークシートのフォーマットを設定
            // ヘッダ行のスタイルを設定
            sheet.Rows[0].Style.Color = Color.FromArgb(229, 243, 251);
            sheet.Rows[0].Style.Font.FontName = "Yu Mincho";
            sheet.Rows[0].Style.Font.Size = 14f;
            sheet.Rows[0].BorderAround(); // ヘッダ行に外枠を追加
            sheet.Rows[0].Borders.Color = Color.FromArgb(180, 180, 180); // 枠線の色を設定

            // データ行のスタイルを設定
            for (int i = 1; i < sheet.AllocatedRange.Rows.Count(); i++)
            {
                sheet.Rows[i].Style.Color = Color.FromArgb(247, 252, 255);
                sheet.Rows[i].Style.Font.FontName = "Yu Mincho";
                sheet.Rows[i].Style.Font.Size = 12f;
                // 偶数行の背景色を変更
                if ((i + 1) % 2 == 0)
                {
                    sheet.Rows[i].Style.Color = Color.FromArgb(255, 255, 255);
                }
            }
            sheet.Range[2, 1, sheet.Rows.Count(), sheet.Columns.Count()].BorderInside(); // データ行セルの内枠を追加
            sheet.Range[2, 1, sheet.Rows.Count(), sheet.Columns.Count()].Borders.Color = Color.FromArgb(220, 220, 220); // 枠線の色を設定

            // 列幅を内容に合わせて調整
            for (int j = 1; j <= sheet.AllocatedRange.Columns.Count(); j++)
            {
                sheet.AutoFitColumn(j);
            }

            // ワークブックをメモリストリームに保存
            MemoryStream stream = new MemoryStream();
            workbook.SaveToStream(stream, FileFormat.Version2016);

            // ストリームの内容をファイルに書き込む
            File.WriteAllBytes("output/ストリームで作成したExcelファイル.xlsx", stream.ToArray());

            // リソースを解放
            workbook.Dispose();
        }
    }
}
```

実行結果
![C#でExcelをバイトストリームとして作成・保存](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/71289bd0-07b6-37ae-6014-30872dd24694.png)

## C#でバイトストリームからExcelを読み取る

`Workbook.LoadFromStream()`メソッドを使用して、Excelファイルのストリームを`Workbook`インスタンスにロードし、`Workbook.Worksheets[]`プロパティを介してワークシートにアクセスします。その後、`Worksheet.Range[].Value`プロパティを使用してセルデータを直接読み取り、さらなる操作を行います。以下はその手順の例です：

1. `Workbook`インスタンスを作成します。
2. `Workbook.LoadFromStream()`メソッドを使用して、新規または既存のバイトストリームからExcelワークブックをロードします。
3. `Workbook.Worksheets[]`プロパティを使用して指定のワークシートにアクセスします。
4. ワークシートで使用されているセル範囲を行と列でループし、`Worksheet.Range[].Value`プロパティを使用してセルデータを取得します。
5. 取得したデータを出力するか、他の処理に利用します。

**コード例**
```csharp
using Spire.Xls;

namespace LoadExcelStream
{
    class Program
    {
        static void Main(string[] args)
        {
            // Workbookクラスのインスタンスを作成
            Workbook workbook = new Workbook();

            // メモリストリームを作成
            MemoryStream stream = new MemoryStream();
            File.OpenRead("output/ストリームで作成したExcelファイル.xlsx").CopyTo(stream);

            // メモリストリームからExcelファイルを読み込む
            workbook.LoadFromStream(stream);

            // ワークブックの最初のワークシートを取得
            Worksheet sheet = workbook.Worksheets[0];

            // ワークシートから抽出したデータを格納するリストを初期化
            List<List<string>> data = new List<List<string>>();
            for (int i = 0; i < sheet.AllocatedRange.Rows.Count(); i++)
            {
                // 各行のデータを格納するリストを作成
                List<string> lines = new List<string>();
                for (int j = 0; j < sheet.AllocatedRange.Columns.Count(); j++)
                {
                    // セルの値を取得して現在の行のリストに追加
                    lines.Add(sheet.AllocatedRange[i + 1, j + 1].Value);
                }
                // 現在の行のデータをデータリストに追加
                data.Add(lines);
            }

            // 抽出したデータを出力または後続の操作に使用
            foreach (List<string> lines in data)
            {
                Console.WriteLine(string.Join(" | ", lines));
            }
        }
    }
}
```

実行結果
![C#でバイトストリームからExcelを読み取る](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/8c37c7ff-5283-46a3-5a77-536f80a91390.png)

## C#でバイトストリームを介してExcelを編集

`Workbook`の`LoadFromStream()`メソッドを使用すると、バイトストリームからExcelワークブックをロードできます。その後、ライブラリの他のメソッドやプロパティを使用してワークブックの内容を編集できます。編集後は、`SaveToStream()`メソッドを再度使用して、ワークブックをバイトストリームに保存することで、ストリームを介した操作のみでExcelファイルを編集できます。以下はその手順の例です：

1. `Workbook`インスタンスを作成します。
2. `Workbook.LoadFromStream()`メソッドを使用して、新規または既存のバイトストリームからExcelワークブックをロードします。
3. `Workbook.Worksheets[]`プロパティを使用して指定のワークシートにアクセスします。
4. `CellRange`の`Style`や`Value`プロパティを利用してセルまたはセル範囲を編集します。
5. `Workbook.SaveToStream()`メソッドを使用して、Excelワークブックを再びバイトストリームに保存します。
6. リソースを解放します。

**コード例**
```csharp
using Spire.Xls;
using System.Drawing;

namespace ModifyExcelStream
{
    class Program
    {
        static void Main(string[] args)
        {
            // Workbook クラスの新しいインスタンスを作成
            Workbook workbook = new Workbook();

            // メモリストリームを作成
            MemoryStream stream = new MemoryStream();
            File.OpenRead("output/ストリームで作成したExcelファイル.xlsx").CopyTo(stream);

            // メモリストリームから Excel ファイルを読み込む
            workbook.LoadFromStream(stream);

            // ワークブックの最初のワークシートを取得
            Worksheet sheet = workbook.Worksheets[0];

            // ヘッダ行のスタイルを変更
            CellRange headerRow = sheet.AllocatedRange.Rows[0];
            headerRow.Style.Font.FontName = "Yu Gothic UI";
            headerRow.Style.Font.Size = 12f;
            headerRow.Style.Color = Color.FromArgb(108, 91, 123);
            headerRow.Borders.Color = Color.FromArgb(255, 255, 255);

            // データ行のスタイルを変更
            for (int i = 1; i < sheet.AllocatedRange.Rows.Count(); i++)
            {
                CellRange dataRow = sheet.AllocatedRange.Rows[i];
                dataRow.Style.Font.FontName = "Yu Gothic UI";
                dataRow.Style.Font.Size = 10f;
                dataRow.Style.Color = Color.FromArgb(255, 204, 128);
                dataRow.Borders.Color = Color.FromArgb(158, 158, 158);
                // 偶数行の色を変更
                if (i % 2 == 0)
                {
                    dataRow.Style.Color = Color.FromArgb(129, 222, 227);
                }
            }

            // 列の幅を自動調整して内容に合わせる
            for (int k = 1; k <= sheet.AllocatedRange.Columns.Count(); k++)
            {
                sheet.AutoFitColumn(k);
            }

            // セルの境界線の色を変更
            sheet.AllocatedRange.Style.Borders.Color = Color.White;

            // 修正されたワークブックをメモリストリームに保存
            workbook.SaveToStream(stream);

            // ストリームの内容を新しいファイルに書き込む
            File.WriteAllBytes("output/ストリーム経由でExcelファイルを修正.xlsx", stream.ToArray());

            // リソースを解放
            workbook.Dispose();
        }
    }
}
```

実行結果
![C#でバイトストリームを介してExcelを編集](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/93cd0e6f-44e0-744f-a09d-01a2f479b004.png)

本記事では、.NETプラットフォームでC#を使用して、バイトストリームを介してExcelワークブックを作成、読み取り、編集、および保存する方法を紹介しました。