2022年7月15日金曜日

ExcelDataReaderでExcelを高速に読み込む

どうも。ひっくです。

今回は表題の通り、ExcelDataReaderを使用してExcelデータを高速に読み取る方法について

備忘録として残しておこうと思います。

ExcelDataReaderの使用用途、メリット・デメリット


  • 使用用途

    Excel管理しているデータをDBへ保存する。

    Excel管理しているデータを読み込み、集計・分析等別途処理を行う前提データとして活用する。etc.

     

  • メリット

    • 読み込み処理時間がかなり早い

      他Excel読み込みライブラリと比較した結果は色々検証されている方がいるようなので

      そちらを参照していただければと思いますが、読み込みは一番早い処理速度となっていました。

    • 旧形式エクセルファイル(.xls)、新形式エクセルファイル(.xlsx)の両形式が読み取り可能

      他Excel読み込みライブラリでは旧型式エクセルファイルをサポートしていないこともありますが、

      特に事前の設定等必要なく、読み込み対象としてサポートされています。

    • Officeがインストールされていない環境でも使用可能

    • MITライセンスで商用利用可能

  • デメリット

    • 読み込み処理しかできない

      書き込み処理はサポートされていません。書き込みは別ライブラリを使用する必要があります。

    • 罫線情報やセル参照の名前定義等は読み込まれない情報がある。

      Microsoft.Office.Interop.Excel(Com参照)等で取得可能な情報は、あまり取得できないようです。

 

動作環境と公式GitHubについて


 

実際に使用してみる


今回確認は以下で実施しています。

OS: Windows11

Target Framework: .NetCore3.1

VisualStudio: 2022 Community

 

導入手順は以下の通りです。

  1. NuGetから「ExcelDataReader」「ExcelDataReader.DataSet」をインストールします。

  2. ExcelDataReaderを参照し、読み込み用メソッドを用意しておきます。

    以下サンプルを使用してExcelファイルを読み込むと、DataTable型でExcelのデータを取得することができます。

using ExcelDataReader;
using System;
using System.Data;
using System.IO;
using System.Text;

namespace ExcelDataReaderTest
{
    public class ExcelCsvDataReader
    {
        public DataTable ReadExcelData(string path, string sheetName = null, string passsword = null)
        {
            DataTable data = null;

            try
            {
                // .NetCoreの場合、Encodingが足りないので以下1行が必要になる(.NETFrameworkでは不要)
                Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                using var stream = File.Open(path, FileMode.Open, FileAccess.Read);
                var excelReaderConfig = new ExcelReaderConfiguration();
                if (passsword != null)
                {
                    excelReaderConfig.Password = passsword;
                }

                using var reader = ExcelReaderFactory.CreateReader(stream, excelReaderConfig);
                DataSet ds = reader.AsDataSet();
                data = string.IsNullOrEmpty(sheetName) ? ds.Tables[0] : ds.Tables[sheetName];
            }
            catch (Exception)
            {
                throw;
            }

            return data;
        }
    }
}

 

変数「ds」をビジュアライザーで開いたのが以下になります。

各シートがそれぞれ読み込まれているのが分かりますね。

「各歳別人口1」シートの取得結果は以下になります。

見ていただければ分かりますが、A列から順に「Column0」を起点として自動的に列名が割り振られます。

このとき、データへアクセスするために列名を列Indexに変換するような処理が必要になってきます。

以下のようなメソッド「列名⇒列Index変換」「列番号⇒列名変換」等を適宜作成の上、読み込む列名・列番号を

変換して使用すれば良いかと思われます。(実装内容についても必要に応じ、適宜変更してください)

        private string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        public string NumberToColumnName(int columnNumber)
        {
            var sb = new StringBuilder();
            for (; 0 < columnNumber; columnNumber = (columnNumber - 1) / 26)
            {
                int n = (columnNumber - 1) % 26;
                sb.Append(alphabet.Substring(n, 1));
            }

            return sb.ToString();
        }
        
        public int ColumnNameToColumnIndex(string columnName)
        {
            int number = 0;

            if (!Regex.IsMatch(columnName.ToUpper(), @"^[A-Z]+$"))
            {
                throw new FormatException("引数はアルファベットのみを指定してください");
            }

            for (int i = 0; i < columnName.Length; i++)
            {
                int n = alphabet.IndexOf(columnName.Substring(i, 1)) + 1;
                number += n * (int)Math.Pow(26, columnName.Length - i - 1);
            }

            return number - 1;
        }

 

ExcelDataReader導入時の注意点


上記サンプルコードのコメントにも付記していますが、.NetCoreをTarget Frameworkに指定している場合

NuGetで「System.Text.Encoding.CodePages」をインストール(※)の上、以下の行を追加しないと例外が発生します。

例外発生時のメッセージは以下の通りです。

「System.NotSupportedException: 'No data is available for encoding 1252. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.'」

 

※ NuGetで「System.Text.Encoding.CodePages」をインストール

 

まとめ


以上、ExcelDataReaderを使用して高速にExcelを読み込む方法について、まとめました。

高速にExcelを読み込みたい場合、読み込み処理のみが必要な場合等は、このライブラリを使用すれば良いのではないでしょうか。

なお、CSVファイルについても同様に読み込みが可能だったりします。

次回はCSVファイルの読み込み方法についても紹介します。

 

今回はこのへんで。ではまた!

0 件のコメント:

コメントを投稿