動作環境
- 実装
- C++ Builder XE4
- 確認
- Windows 8.1 Pro
- Excel 2016
処理概要
- ファイルを開く
- Excel + OLEでの値代入
- Range選択、コピー・ペースト
- ファイルを保存
5行5列のセルへの値代入を高速化できないか。
処理速度の検討
C++ Builder XE4 > Excel + OLE > 5x5代入、コピー、ペーストの処理時間
の記事において、5行5列のセルの値代入に4.9秒かかっている。
Excel 2013 vs Excel 2010 Ole or interop performance
を見つけた。
Excel 2013になってからOLE関連で処理が遅くなったようだ。
OLE2.set_property( Application, 'ScreenUpdating', FALSE);
で対応するとあり、試してみた。
code
Uni1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <System.Win.ComObj.hpp> // EXCEL処理用
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
String curDir = ExtractFileDir(Application->ExeName);
WideString srcFile = curDir + "\\base.xlsx";
WideString dstFile = curDir + "\\out.xlsx";
//--- Excel処理
bool closeExcel = false;
Variant ExcelApp = CreateOleObject("Excel.Application");
DWORD stTim = GetTickCount();
try
{
Variant xls_books;
Variant xls_abook;
Variant xls_sheets;
Variant xls_asheet;
try {
Memo1->Lines->Add(L"start: " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz"));
ExcelApp.OlePropertySet("Visible", false); // Excel not shown
ExcelApp.OlePropertySet("DisplayAlerts", false); // No dialog for overwrite
#if 1 // 2018/07/06
ExcelApp.OlePropertySet("ScreenUpdating", false);
#endif
xls_books = ExcelApp.OlePropertyGet("Workbooks");
xls_abook = xls_books.OleFunction("Open", srcFile);
// 最初のシート選択
xls_abook.OlePropertyGet("Sheets", 1).OleProcedure("Select");
xls_asheet = xls_abook.OlePropertyGet("ActiveSheet");
Memo1->Lines->Add(L"start:Fill " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz"));
// 1. Fill
for (int ci = 1; ci <= 5; ci++) { // ci: column index
for (int ri = 1; ri <= 5; ri++) { // ri: row index
xls_asheet.OlePropertyGet("Cells", ri, ci).OlePropertySet("Value", WideString("3.141592"));
}
}
Memo1->Lines->Add(L"fin:Fill " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz"));
// 2. Copy and Paste
Variant wrkRange = xls_asheet.OlePropertyGet("Range", WideString("A1:E5"));
wrkRange.OleProcedure("Copy");
xls_asheet.OlePropertyGet("Cells", 7, 7).OleProcedure("Select");
xls_asheet.OleProcedure("Paste");
Memo1->Lines->Add(L"fin:Copy " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz"));
// 3. Save
#if 1 // 2018/07/06
ExcelApp.OlePropertySet("ScreenUpdating", true);
#endif
xls_abook.OleProcedure("SaveAs", dstFile); //開いた*.xlsxを別名保存
closeExcel = true;
ExcelApp.Exec(Procedure("Quit"));
Memo1->Lines->Add(L"fin:Save " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz"));
DWORD edTim = GetTickCount();
String msg = IntToStr((int)(edTim - stTim)) + L"(msec) has passed";
msg = msg + L"\r\n" + L"Save to [" + dstFile + L"]";
ShowMessage(msg);
}
__finally
{
xls_asheet = Unassigned(); // 変数を初期状態に
xls_sheets = Unassigned();
xls_abook = Unassigned();
xls_books = Unassigned();
}
}
__finally
{
ExcelApp = Unassigned();
}
}
//---------------------------------------------------------------------------
結果
下記は対処前の結果。
- ファイルオープン: 21.9秒
- 5行5列の代入: 4.9秒
- コピーとペースト: 1.1秒
- 保存: 19.7秒
下記は対処後 (ScreenUpdatingをfalse)。
- ファイルオープン: 22.4秒
- 5行5列の代入: 1.3秒 (高速化した)
- コピーとペースト: 0.3秒 (高速化した)
- 保存: 19.4秒
全体で43.485秒。