- PR -

C#(VSTO) 配列経由でセルの値を高速で読み書きする方法

1
投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2005-06-04 11:36
C#(VSTO) 配列経由でセルの値を高速で読み書きする方法

課題1
C#の二次元配列の値をセルに一括で書き込みたい。
専用メソッド(SetValue)を作成したがパフォーマンスをより向上させたい。
課題2
セルの値をC#の二次元配列に一括で読み込みたい。
専用メソッド(GetValue)を作成したがパフォーマンスを向上させたい。

環境
VisualStudioTools for OfficeSystem 経由でC#からExcel2003を制御
一括で読み書きする件数は数千件程度

疑問1
セルに書き込んでいる時だけExcelの計算方法を自動計算から手動計算に
切り替えることができれば確実にパフォーマンスが向上すると考えている。
C#からExcelの計算方法を変更する方法が分からない。
疑問2
現在は、セル1個ずつに対して値を読み書きしているからパフォーマンスが
芳しくないのではと思っている。
箱型の領域(Range)に対して一括で読み書きするもっと効率の良い方法があるか?
疑問3
タブと改行で区切られた巨大な文字列を生成して一括で貼り付けるの方法は
検討の価値があるか?


以下、読み書き専用のクラス

namespace Excel連携テスト
{
using System;
using Excel = Microsoft.Office.Interop.Excel;

public class Bridge
{
public Bridge(Excel.Workbook workbook)
{
thisWorkbook = workbook;
}

public void GetValue(object[,] cellValue,string sheetName,int rowIndex,int columnIndex)
{
Excel.Worksheet worksheet1 = thisWorkbook.Worksheets.get_Item(sheetName) as Excel.Worksheet;

int rowLength = cellValue.GetLength(0);
int columnLength = cellValue.GetLength(1);

for(int i = 0;i < rowLength;i++)
{
for(int j = 0;j < columnLength;j++)
{
cellValue[i,j] = (worksheet1.Cells.get_Item(rowIndex+i,columnIndex+j) as Excel.Range).Value2;
}
}
}

public void SetValue(object[,] cellValue,string sheetName,int rowIndex,int columnIndex)
{
Excel.Worksheet worksheet1 = thisWorkbook.Worksheets.get_Item(sheetName) as Excel.Worksheet;

int rowLength = cellValue.GetLength(0);
int columnLength = cellValue.GetLength(1);

for(int i = 0;i < rowLength;i++)
{
for(int j = 0;j < columnLength;j++)
{
(worksheet1.Cells.get_Item(rowIndex+i,columnIndex+j) as Excel.Range).Value2 = cellValue[i,j];
}
}
}


private Excel.Workbook thisWorkbook;
}
}

以下、専用クラスの呼び出し例

protected void ThisWorkbook_Open()
{
Bridge bridge1 = new Bridge(thisWorkbook);
object[,] object1 = new object[1000,2];
for(int i = 0;i < object1.GetLength(0);i++)
{
for(int j = 0;j < object1.GetLength(1);j++)
{
object1[i,j] = i+j*1000;
}
}
DateTime time1 = DateTime.Now;
bridge1.SetValue(object1,"Sheet1",1,1);
object[,] object2 = new object[1000,2];
bridge1.GetValue(object2,"Sheet1",1,1);
bridge1.SetValue(object2,"Sheet1",1,5);
DateTime time2 = DateTime.Now;
TimeSpan timeSpan1 = time2.Subtract(time1);
object[,] answer1;
answer1 = new object[1,1];
answer1[0,0] = String.Format("経過={0:00}:{1:00}:{2:00}.{3:000}",timeSpan1.Hours,timeSpan1.Minutes,timeSpan1.Seconds,timeSpan1.Milliseconds);
bridge1.SetValue(answer1,"Sheet1",1,10);

}
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2005-06-04 16:19
画面更新の制御は
thisApplication.ScreenUpdating = false;
thisApplication.ScreenUpdating = true;
自動計算の制御は
thisApplication.Calculation = Excel.XlCalculation.xlCalculationManual;
thisApplication.Calculation = Excel.XlCalculation.xlCalculationAutomatic;
でできることが分かった。
セルに書き込む間、画面更新を無効、手動計算にしたが、
期待したほどの速度改善ができなかった。
実験にしてみたが、マクロによる同様の書き込み処理に比べ約20%
遅い程度なので見方によってはかなり健闘しているとも言えるが、
ロジックを改良してもっとパフォーマンスを上げたい。
良いアイデアは無いだろうか。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-06-07 06:15
"エクセル 配列"を、Insider.NETから検索
@IT > Insider.NET > Insider.NET 会議室 > ディレクトリ > Office > Excel/CSV
Excelへの転送処理
配列のデータをEXCELにペーストする
VB.VETで、処理速度を早くしたいのですが

_________________
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2005-06-07 14:41
VSTO+C#でもこの手法が使えればパフォーマンスの更なる向上が
期待できます。ご回答ありがとうございます。
1

スキルアップ/キャリアアップ(JOB@IT)