2
0

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 3 years have passed since last update.

C#でExcel操作の処理時間を計測してみた (Microsoft.Office.Interop.Excel)

Last updated at Posted at 2021-02-06

計測した項目

  1. セル取得 Cells[,]
  2. セル値取得 Range.Value
  3. セル値2取得 Range.Value2
  4. セル値Text取得 Range.Text
  5. セル値設定 Range.Value = xxx
  6. セル範囲取得 Range[Cells[,],Cells[,]]
  7. 罫線取得 Range.Borders
  8. 罫線辺取得 Borders[]
  9. 罫線辺設定 Border.LineStyle = xxx

測定結果

10000回実行したときの平均時間(ミリ秒)

No 内容 ケースA ケースB ケースC
1 セル取得 1.024 0.975 5.221
2 セル値取得 0.165 0.158 1.118
3 セル値2取得 0.135 0.131 0.682
4 セル値Text取得 0.203 0.196 1.170
5 セル値設定 0.301 0.302 0.992
6 セル範囲取得 4.288 4.265 20.211
7 罫線取得 0.968 0.882 5.012
8 罫線辺取得 0.915 0.919 5.299
9 罫線辺設定 0.873 0.834 3.391
  • ケースA ・・・ 新規ブックに対して実行
  • ケースB ・・・ ケースA実行後のブックに対して実行
  • ケースC ・・・ 約10000×20個のデータが入力されているブック(ケースA,Bをまとめ作業してたブック)に対して実行(下記1

image.png

測定結果に対する考察

  • セル範囲取得や罫線情報へのアクセスに時間がかかるようである。
  • 全ての項目でケースCの時間がケースA,Bよりもかかっており、大量のデータを含むExcelファイルに対しては各種操作の実行時間がかなり伸びるようである。

回数方向の傾向をみてみる

10000回の実行中に実行時間が伸びていくのかを見てみた。
結果としては、伸びてはいかないが、時々極端に時間がかかるタイミングがある。
メモリ解放処理(GC)が走っている?

下図は、ケースCの、項目6 セル範囲取得 の結果をプロットしたもの。※縦軸の単位は[秒]
image.png

測定用コード


using System;
using System.Diagnostics;
using System.Runtime.CompilerServices; // to use [MethodImpl(MethodImplOptions.NoInlining)]
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

class ExcelSample
{
    static void DumpElapsSec(string mark, Stopwatch sw)
    {
        double sec = (double)sw.ElapsedTicks / (double)Stopwatch.Frequency;
        Console.Write(mark+"\t");
        Console.WriteLine(sec);

    }


    //[MethodImpl(MethodImplOptions.NoInlining)]
    [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] // 最適化抑制
    static void OverwriteActiveSheet()
    {
        Excel.Application oExcelApp = null;
        Excel.Worksheet oSheet = null;
        
        try {
            oExcelApp = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
        }
        catch ( System.Runtime.InteropServices.COMException ) {
            Console.WriteLine("Failed to get Excel.Application.");
            return;
        }
        
        try {
            var oBook = (Excel.Workbook)oExcelApp.ActiveWorkbook;
            if ( oBook != null ) {
                oSheet = (Excel.Worksheet)oBook.ActiveSheet;
            }
        }
        catch ( System.Runtime.InteropServices.COMException ) {
        }
        if ( oSheet == null ) {
            Console.WriteLine("Failed to get ActiveWorkbook or ActiveSheet.");
            return;
        }


        var sw = new Stopwatch();
        bool screenUpdatingBackup = oExcelApp.ScreenUpdating;

        Excel.XlCalculation calcModeBackup = oExcelApp.Calculation;
        try {
            oExcelApp.ScreenUpdating = false; // 画面更新の停止
            oExcelApp.Calculation = Excel.XlCalculation.xlCalculationManual; // 再計算の停止
            

            // セルの読み込み
            Excel.Range oCells = oSheet.Cells;
            

            for ( int row=1;row<=10000;row++ ){
                sw.Restart();
                var oRange = oCells[row, 2] as Excel.Range; // B列row行セル
                sw.Stop();
                DumpElapsSec("1", sw);

                sw.Restart();
                object a = oRange.Value;
                sw.Stop();
                DumpElapsSec("2", sw);

                sw.Restart();
                object b = oRange.Value2;
                sw.Stop();
                DumpElapsSec("3", sw);

                sw.Restart();
                object c = oRange.Text;
                sw.Stop();
                DumpElapsSec("4", sw);
                //Console.Error.WriteLine(a);
                //Console.Error.WriteLine(b);
                //Console.Error.WriteLine(c);

                // セルへの書き込み
                oRange = oCells[row, 3] as Microsoft.Office.Interop.Excel.Range;
                sw.Restart();
                oRange.Value = "hoge";
                sw.Stop();
                DumpElapsSec("5", sw);

                // 罫線を引く
                Excel.Borders oBorders;
                Excel.Border oBorder;
                sw.Restart();
                oRange = oSheet.Range[oSheet.Cells[row, 2], oSheet.Cells[row+2, 4]];
                sw.Stop();
                DumpElapsSec("6", sw);

                sw.Restart();
                oBorders = oRange.Borders;
                sw.Stop();
                DumpElapsSec("7", sw);

                sw.Restart();
                oBorder = oBorders[Excel.XlBordersIndex.xlEdgeBottom];// xlEdgeLeft xlEdgeRight xlEdgeTop
                sw.Stop();
                DumpElapsSec("8", sw);

                sw.Restart();
                oBorder.LineStyle = Excel.XlLineStyle.xlContinuous;
                sw.Stop();
                DumpElapsSec("9", sw);
            }
        }
        finally {
            if ( oExcelApp.Calculation != calcModeBackup ) {
                oExcelApp.Calculation = calcModeBackup;
            }
            if ( oExcelApp.ScreenUpdating != screenUpdatingBackup ) {
                oExcelApp.ScreenUpdating = screenUpdatingBackup;
            }
        }
    }

    [STAThread]
    static void Main(string[] args)
    {
        OverwriteActiveSheet();
    }
}

上記の出力データの整形用コード


using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;


class FilterTextRow
{
    static readonly int N = 9;

    [STAThread]
    static void Main(string[] args)
    {
        if(args.Length==0){return;}

        Regex r = new Regex("^([0-9]+)\t(.*)$");

        string[] lines = File.ReadAllLines(args[0]);

        var sb = new StringBuilder();
        for(int i=0;i+N-1<lines.Length;i+=N){
            for(int k=0;k<N;k++){
                Match m = r.Match(lines[i+k]);
                //if(m.Success){
                    if (k>0){sb.Append("\t");}
                    sb.Append(m.Groups[2].Value);
                //}// else error
            }
            sb.Append("\n");
        }
        Console.Write(sb.ToString());
    }
}

参考サイト

以下は、記事を書いた後に見つけたサイト

  1. 実行した際は、行(11~10002行目)を非表示にはしていない

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?