LoginSignup
10
16

More than 3 years have passed since last update.

[C#]Excelファイルのセル読取/書込

Last updated at Posted at 2019-10-24

D&DしたPDFファイルをSQL Serverに登録+プレビューする方法の記事の一部になります。

4. C#:Excelファイル書き換え

Excelファイルのセル読取/書込処理の忘備録になります。

1) C#でExcelファイルを書き換える方法

大きく分けて、下記の2つがあります。

  • Microsoft.Office.Interop.Excel を使った COM 参照による方法
  • オープンソースライブラリを使用する方法

2) Microsoft.Office.Interop.Excelを使う方法

メリット

  • COM 参照なので、現行形式 (.xlsx) だけでなく、旧型式 (.xls)、CSV 形式 (.csv)、マクロ付きも利用可能です。

デメリット

  • 処理が遅い
  • Excelのインストールが必須
  • プロセス解放漏れのリスクがある

サンプルコード

using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

    class ExcelManager : IDisposable
    {
        /// <summary>
        /// Excel操作用オブジェクト
        /// </summary>
        private Application _application = null;
        private Workbook _workbook = null;
        private Worksheet _worksheet = null;

        // Dispose処理は、下記のページを参考にしています。
        // [アンマネージドリソースをDisposeパターンで管理する]
        // (https://days-of-programming.blogspot.com/2018/04/dispose.html)

        #region "IDisposable Support"
        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: Managed Objectの破棄
                }

                if (_workbook != null)
                {
                    _workbook.Close();
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(_workbook);
                    _workbook = null;
                }

                if (_application != null)
                {
                    _application.Quit();
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(_application);
                    _application = null;
                }

                disposedValue = true;
            }
        }

        ~ExcelManager()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion "IDisposable Support"

        /// <summary>
        /// Excelワークブックを開く
        /// </summary>
        public void Open()
        {
            try
            {
                // Excelアプリケーション生成
                _application = new Application()
                {
                    // 非表示
                    //Visible = true
                    Visible = false
                };

                // Bookを開く
                _workbook = _application.Workbooks.Open(@"e:\book1.xlsx");

                // 対象シートを設定する
                _worksheet = _workbook.Worksheets["Sheet1"];
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// Excelワークブックをファイル名を指定して保存する
        /// </summary>
        /// <returns>True:正常終了、False:保存失敗</returns>
        public bool SaveAs()
        {
            try
            {
                // ファイル名を指定して保存する
                _workbook.SaveCopyAs(@"e:\book2.xlsx");
            }
            catch
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// セル設定
        /// </summary>
        /// <param name="rowIndex">row</param>
        /// <param name="columnIndex">col</param>
        /// <param name="value">value</param>
        public void WriteCell(int rowIndex, int columnIndex, object value)
        {
            // セルを指定
            var cells = _worksheet.Cells;
            var range = cells[rowIndex, columnIndex] as Range;

            // 値を設定
            range.Value = value;

            // cell解放
            Marshal.ReleaseComObject(range);
            Marshal.ReleaseComObject(cells);
        }
    }

参考

Excelファイルを C# と VB.NET で読み込む "正しい" 方法
アンマネージドリソースをDisposeパターンで管理する
Excel操作クラス
Excel操作クラス

3) オープンソースライブラリを使用する方法

オープンソースライブラリとして EPPlus を想定しています。
(当初は NPOI を試用しましたが、透過図形がコピーできず、諦めました)

メリット

  • コア部分が Microsoft の純正ライブラリであるという安心感?
  • NPOI よりも扱いやすい

デメリット

  • Open XML 規格用に作られたものであるため、旧形式ファイル (.xls) を読み込むことができない

準備

メニューの [ツール] - [NuGet パッケージ マネージャー] から、「EPPlus」を検索してインストールします。

サンプルコード

ExcelManagerEx.cs
using OfficeOpenXml;

    class ExcelManagerEx
    {
        /// <summary>
        /// Excel操作用オブジェクト
        /// </summary>
        private ExcelPackage _excelPackage = null;
        private ExcelWorksheet _excelWorksheet = null;

        /// <summary>
        /// Excelワークブックを開く
        /// </summary>
        public void Open()
        {
            try
            {
                // Excelファイルを開く
                var fileInfo = new FileInfo(@"e:\book1.xlsx");
                _excelPackage = new ExcelPackage(fileInfo);

                // シート名で参照
                _excelWorksheet = _excelPackage.Workbook.Worksheets["Sheet1"];
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// Excelワークブックをファイル名を指定して保存する
        /// </summary>
        /// <param name="filename">ファイル名</param>
        /// <returns>True:正常終了、False:保存失敗</returns>
        public bool SaveAs(string filename)
        {
            try
            {
                var fileInfo = new FileInfo(filename);
                _excelPackage.SaveAs(fileInfo);
            }
            catch
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// セル書込(R1C1形式)
        /// </summary>
        /// <param name="row">row</param>
        /// <param name="col">col</param>
        /// <param name="value">value</param>
        public void WriteCell(int row, int col, object value)
        {
            // 値を書込
            _excelWorksheet.Cells[row, col].Value = value;
        }

        /// <summary>
        /// セル書込("A1"形式)
        /// </summary>
        /// <param name="address">address("A1"形式)</param>
        /// <param name="value">value</param>
        public void WriteCell(string address, object value)
        {
            // 値を書込
            _excelWorksheet.Cells[address].Value = value;
        }

        /// <summary>
        /// セル読取(R1C1形式)
        /// </summary>
        /// <param name="row">row</param>
        /// <param name="col">col</param>
        /// <returns>セルの値</returns>
        public object ReadCell(int row, int col)
        {
            // セル読取
            return _excelWorksheet.Cells[row, col].Value;
        }

        /// <summary>
        /// セル読取("A1"形式)
        /// </summary>
        /// <param name="address">address("A1"形式)</param>
        /// <returns>セルの値</returns>
        public object ReadCell(string address)
        {
            // セル読取
            return _excelWorksheet.Cells[address].Value;
        }

        /// <summary>
        /// レンジ読取(R1C1R2C2形式)
        /// </summary>
        /// <param name="rowFrom">row From</param>
        /// <param name="colFrom">col From</param>
        /// <param name="rowTo">row To</param>
        /// <param name="colTo">col To</param>
        /// <returns>レンジ</returns>
        public object[,] ReadRange(int rowFrom, int colFrom, int rowTo, int colTo)
        {
            // レンジ読取
            return (object[,])_excelWorksheet.Cells[rowFrom, colFrom, rowTo, colTo].Value;
        }

        /// <summary>
        /// レンジ読取("A1:B2"形式)
        /// </summary>
        /// <param name="address">address("A1"形式)</param>
        /// <returns>レンジ</returns>
        public object[,] ReadRange(string addresso)
        {
            // レンジ読取
            return (object[,])_excelWorksheet.Cells[addresso].Value;
        }
    }
test.cs
using System;
using System.Windows.Forms;

    public partial class test: Form
    {
        public test()
        {
            InitializeComponent();
        }

        private void Btn1_Click(object sender, EventArgs e)
        {
            var excelEx = new ExcelManagerEx();
            excelEx.Open();

            // セル書込(R1C1形式)
            excelEx.WriteCell(row: 1, col: 1, value : "test");
            // セル書込("A1"形式)
            excelEx.WriteCell(address: "A1", value: 3.1415926538);

            // セル読取(R1C1形式)
            var cellValue1 = excelEx.ReadCell(row: 1, col: 1);
            // セル読取("A1"形式)
            var cellValue2 = excelEx.ReadCell("A1");
            // レンジ読取(R1C1R2C2形式)
            var rangeValue1 = excelEx.ReadRange(rowFrom: 1, colFrom: 1, rowTo: 2, colTo: 2);
            // レンジ読取("A1:B2"形式)
            var rangeValue2 = excelEx.ReadRange("A1:B2");
            // 2次元配列(0始まり)から要素を参照
            var a = rangeValue2[0, 0];    // aには、3.1415926538が入る

            // 名前を付けて保存する
            if (excelEx.SaveAs(@"e:\book2.xlsx") == false)
            {
                MessageBox.Show("ファイルが既に開かれています。\n閉じてから、再試行してください。",
                    "エラー",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }
    }

参考

[C#] EPPlusでExcelの基本操作
EPPlusの使い方(目次)

10
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
16