14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Excel書き込みの実行速度調査について

Last updated at Posted at 2019-07-30

Excel書き込みの実行速度について

C++でExcelを高速に操作したい!との思いから、様々なAPIの実行速度を測定してみました。
今回、利用したい機能は、書き込みなので、書き込み時間しか調査していません。

■40200回セルに書き込みを行った結果

言語 手法 xls xlsx 実行時間
C# NPOI (xls) × 96.4 ms
C# EPPlus (xlsx) × 243.2 ms
C++ ExcelCreater (Ver 3.0.3.44.12) × 434.7 ms
Python xlwt (読み込みはxlrd) × 458.6 ms
C# NPOI (xlsx) × 582.0 ms
C# ClosedXML × 667.2ms
Python openpyxl × 965.6 ms
C++ ExcelCreater (Ver 2.0.8.1) × 8040.5 ms
C++ Microsoft Excel 11.0 Object Library × 14171.9 ms
C# OpenXML × 2363686 ms

各APIの実行時間について

.NET系のAPIは、初回実行時に「平均の時間+300ms」ほど時間がかかっていました。
そのため、初回の実行時間を除いた50回の平均時間を算出しています。

.NETアプリの実行テクニック

初回実行時に時間がかかる問題を解決するために、以下の2点についても調査してみようと思います。

  1. .NET起動時に読み込む
  2. ネイティブ展開
    「C# .NET 速度」←検索キーワード

OpenXMLの実行時間について

目を疑うほど遅かったです。もしかすると、実装方法に問題が有るのかもしれません。

まとめ

・「xls」と「xlsx」の最速を目指す場合

言語 手法 xls xlsx 実行時間
C# NPOI (xls) × 96.4 ms
C# EPPlus (xlsx) × 243.2 ms

・使用モジュールを1つにする場合

言語 手法 xls xlsx 実行時間
C# NPOI (xls) × 96.4 ms
C# NPOI (xlsx) × 582.0 ms

今後について

xlsxのみの対応で良かったので、EPPlusを利用する事にしました。
C++から呼び出すことができる、エクセル操作DLLをC#で作成しようと思います。

NPOI

導入方法

  1. NuGet パッケージの管理の画面から NPOI をインストールします。
     ※NuGetが最新で無い場合はエラー発生の可能性有り。更新してください。
  2. using NPOI; 」が読み込めればインストール完了です。

使用方法

PDFにまとまっている資料です。
NPOI の使い方

NPOIのコード例

NPOI.cs
        public static void Check(string Ver)
        {
            int length = 200;

            try
            {
                string filePath = Directory.GetCurrentDirectory() + "\\NPOI_XML." + Ver;

                //ブック作成
                var book = CreateNewBook(filePath);

                //シート無しのexcelファイルは保存は出来るが、開くとエラーが発生する
                book.CreateSheet("Sheet");

                //シート名からシート取得
                var sheet = book.GetSheet("Sheet");

                //セルに設定
                WriteCell(sheet, 0, 0, filePath);

                //
                for (int i = 0; i < length; i++)
                {
                    WriteCell(sheet, 0, i + 1, "【出力確認】");
                    for (int j = 0; j < length; j++)
                    {
                        WriteCell(sheet, j + 1, i + 1, "【確認】i:" + i + "  j:" + j);
                    }
                }

                //ブックを保存
                using (var fs = new FileStream(filePath, FileMode.Create))
                {
                    book.Write(fs);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

                //ブック作成
        static IWorkbook CreateNewBook( string filePath )
        {
            IWorkbook book;
            var extension = Path.GetExtension( filePath );

            // HSSF => Microsoft Excel(xls形式)(excel 97-2003)
            // XSSF => Office Open XML Workbook形式(xlsx形式)(excel 2007以降)
            if( extension == ".xls" ) {
                book = new HSSFWorkbook();
            }
            else if( extension == ".xlsx" ) {
                book = new XSSFWorkbook();
            }
            else {
                throw new ApplicationException( "CreateNewBook: invalid extension" );
            }

            return book;
        }
        //セル設定(文字列用)
        public static void WriteCell( ISheet sheet, int columnIndex, int rowIndex, string value )
        {
            var row = sheet.GetRow( rowIndex ) ?? sheet.CreateRow( rowIndex );
            var cell = row.GetCell( columnIndex ) ?? row.CreateCell( columnIndex );

            cell.SetCellValue( value );
        }

EPPlus

導入方法

  1. NuGet パッケージの管理の画面から EPPlus をインストールします。
     見つからない場合は、NuGetの設定を確認してください。
     ※NuGetが最新で無い場合はエラー発生の可能性有り。更新してください。
  2. using OfficeOpenXml; 」が読み込めればインストール完了です。

使用方法

とても分かりやすく解説してくれています。
EPPlusの使い方

NuGet設定方法

「オプション」→「NuGetパッケージマネージャー」→「パッケージソース」に

ClosedXML

###導入方法

  1. NuGetの更新
    ClosedXMLのインストール時のエラー
    →サイトにはNuGetのバージョンを落とせと書いてあるけど、ClosedXML自体のバージョンを落としてもインストールできます。

  2. NuGet で「ClosedXML」をインストール
    Excelの取り扱いにClosedXMLを使用する

ClosedXMLのコード例

ClosedXML.cs
    class Excel_CHK
    {
        public void Check()
        {
            int length = 200;
            string path = Directory.GetCurrentDirectory() + "\\Check_ClosedXML.xlsx";
            var workbook = new XLWorkbook();
            var worksheet = workbook.Worksheets.Add("Sheet");
            worksheet.Cell("A1").Value = path;
            for (int i = 0; i < length; i++)
            {
                worksheet.Cell(i + 2, 1).Value = "【出力確認】";
                for (int j = 0; j < length; j++)
                {
                    worksheet.Cell(i + 2, j + 2).Value = "【確認】i:" + i + "  j:" + j;
                }
            }
            workbook.SaveAs(path);
        }
    }

openpyxl

導入方法

  1. 実行したい環境に『pip install OpenPyXL』を行う。
  2. import openpyxl as px 」が実行できれば正常に導入できています。

コード例

openpyxl.py
import openpyxl as px
import time
%%time

length = 200

# ファイル名の指定
filename = 'openpyxl_Speed_Check.xlsx'

# ブックの新規作成
wb = px.Workbook()

# シートの選択
ws = wb['Sheet']

# ファイル名の書き込み
ws["A1"].value = filename

# データの書き込み
for i in range(length):
    ws.cell(row=i+2, column=1).value = '【出力確認】'
    for j in range(length):
        ws.cell(row=i+2, column=j+2).value = '【確認】i:{}  j:{}'.format(i, j)
    

# ファイル保存
wb.save(filename)

xlwt

書き込みのみできるPythonライブラリです。
読み込みライブラリは、『xlrd』です。

導入方法

  1. 実行したい環境に『pip install xlwt』を行う。
  2. import xlwt 」が実行できれば正常に導入できています。

コード例

xlwt.py
import xlwt
%%time
wb = xlwt.Workbook()
sheet = wb.add_sheet('Sheet')
# ファイル名の指定
filename = 'xlwt_Speed_Check.xls'

# ファイル名の書き込み
sheet.write(0, 0, filename)

# データの書き込み
for i in range(length):
    sheet.write(i+1, 0, '【出力確認】')
    for j in range(length):
        Temp = '【確認】i:{}  j:{}'.format(i, j)
        sheet.write(i+1, j+1,Temp)
    

# ファイル保存
wb.save(filename)

OpenXML

導入方法

  1. Open XML SDK 2.0 for Microsoft Officeのインストール
     ライブラリのインストーラーを取得し、インストールを行います。
     http://www.microsoft.com/ja-jp/download/details.aspx?id=5124
  2. インストールで生成されたdllファイルをプロジェクトフォルダに移動
     インストール先に指定したフォルダ内の「DocumentFormat.OpenXml.dll」をプロジェクトのフォルダにコピーします。
  3. using DocumentFormat.OpenXml; 」が実行できればインストール完了です。

コード例

OpenXML.cs
    public void Check()
    {
        int length = 200;
        string ExcelFilePath = Directory.GetCurrentDirectory() + "\\Check_OpenXML.xlsx";
        // Excelファイルを作る
        using (SpreadsheetDocument spreadsheetDocument
          = SpreadsheetDocument.Create(ExcelFilePath, SpreadsheetDocumentType.Workbook))
        {
            // ワークブックを用意し、ワークシートを追加する
            WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
            workbookpart.Workbook = new Workbook();
            WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
            worksheetPart.Worksheet = new Worksheet(new SheetData());
            Sheets sheets
              = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
            Sheet sheet = new Sheet()
            {
                Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
                SheetId = 1,
                Name = "Sheet"
            };
            sheets.Append(sheet);

            // セルA1をワークシートに追加する
            writework(1, 1, worksheetPart, ExcelFilePath, CellValues.String);
            for (uint i = 0; i < length; i++)
            {
                writework(1, i + 2, worksheetPart, "【出力確認】", CellValues.String);
                for (uint j = 0; j < length; j++)
                {
                    writework(j + 2, i + 2, worksheetPart, "【確認】i:" + i + "  j:" + j, CellValues.String);
                }
            }

            // ワークブックを保存する
            workbookpart.Workbook.Save();
        }
    }

    private static void writework(uint col, uint row, WorksheetPart WSP, string val, CellValues type)
    {
        Cell cellt = InsertCellInWorksheet(ToAlphabet(col), row, WSP);
        cellt.CellValue = new CellValue(val);
        cellt.DataType = new EnumValue<CellValues>(CellValues.String);
    }

    private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
    {
        Worksheet worksheet = worksheetPart.Worksheet;
        SheetData sheetData = worksheet.GetFirstChild<SheetData>();
        string cellReference = columnName + rowIndex.ToString();
        // 指定された位置のRowオブジェクト
        Row row
          = sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
        if (row == null)
        {
            // Rowオブジェクトがまだ存在しないときは作る
            row = new Row() { RowIndex = rowIndex };
            sheetData.Append(row);
        }
        // 指定された位置のCellオブジェクト
        Cell refCell
          = row.Elements<Cell>().FirstOrDefault(c =>
              c.CellReference.Value == cellReference);
        if (refCell != null)
            return refCell; // すでに存在するので、それを返す
        // Cellオブジェクトがまだ存在しないときは作って挿入する
        Cell nextCell
          = row.Elements<Cell>().FirstOrDefault(c =>
              string.Compare(c.CellReference.Value, cellReference, true) > 0);
        Cell newCell = new Cell() { CellReference = cellReference };
        row.InsertBefore(newCell, nextCell);
        worksheet.Save();
        return newCell;
    }
    public static string ToAlphabet(uint columnNo)
    {
        string alphabet = "ZABCDEFGHIJKLMNOPQRSTUVWXY";
        string columnStr = string.Empty;
        int m = 0;
        do
        {
            m = (int)columnNo % 26;
            columnStr = alphabet[m] + columnStr;
            columnNo = columnNo / 26;
        } while (0 < columnNo && m != 0);
        return columnStr;
    }

14
13
6

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
14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?