- PR -

【VB6】エクセルでコピーのループを行うと処理速度が遅くなる

投稿者投稿内容
SIC
会議室デビュー日: 2005/09/01
投稿数: 14
投稿日時: 2006-08-23 17:13
VB6の質問です。
開発環境は
OS:WindowsXP SP2
Microsoft Office2000
言語:VB6 SP6
です。

VB6で作成したRecordsetのデータをループで
エクセルに貼り付けるというプログラムを作成したのですが、
エクセルのRangeのコピーの処理がループを重ねる度に遅くなっていきます。

ソースは下記のとおりです。
------------------------------------------------------------------------------
Dim rs As ADODB.Recordset
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Dim xlCopyRange As Excel.Range
Dim lngLine As Long 'ページにおけるライン(レコード)数

Set xlApp = CreateObject("Excel.Application")
Set xlBook = xlApp.Workbooks.Open("c:\ExcelFile.xls")
Set xlSheet = xlBook.Worksheets(1)

xlApp.ScreenUpdating = False
xlApp.DisplayAlerts = False
xlApp.EnableAnimations = False
xlApp.EnableAutoComplete = False
xlApp.EnableEvents = False

*************************************
ここにRecordset取得処理が入ります。
*************************************

With xlSheet
.EnableAutoFilter = False
.EnableCalculation = False
.EnableOutlining = False
.EnablePivotTable = False

Set xlCopyRange = .Rows("1:1"))
lngline = 1
Do Until rs.EOF

lngLine = lngLine + 1

'セルの形式をコピー
xlCopyRange.Copy .Rows(CStr(lngline) & ":" & CStr(lngline))

rs.MoveNext

Loop
End With

Set xlSheet = Nothing
Set xlBook = Nothing

xlApp.Quit
Set xlApp = Nothing
------------------------------------------------------------------------------
実際にはセルの形式をコピーした後にRecordsetのデータを貼り付けるのですが、
現在Copyの処理だけでも処理時間が遅くなります。
Timer関数で計ったところ実行直後は0.03秒程度だったコピーの処理時間が
100回くらいループが回ったところで1秒ほどまで遅くなります。
最終的には2000件くらいのデータを扱いたいのでこれでは実用に耐えません。

プログラムの書き方が悪いのか、それとも何か設定があるのかも分からない状態で
ネットで検索してもエクセルのコピーのプログラムはあるのですが、
処理時間まで言及しているHPが見つかりませんでした。

よろしくお願いします。
まどか
ぬし
会議室デビュー日: 2005/09/06
投稿数: 372
お住まい・勤務地: ますのすし管区
投稿日時: 2006-08-23 17:29
引用:

最終的には2000件くらいのデータを扱いたいのでこれでは実用に耐えません。


一つの方法として、2000という数字がわかっているなら、
3000行の書式付き雛形を用意しておき、最後に不要な部分を範囲指定して行削除するではどうでしょうか。
また値の設定もVariant2次元配列で一気にまたは数百行単位で複数回で設定するのも効果があります。
Dim varValue(1 To 3, 1 To 10) As Variant
XXXXX.Range("A1:J3").Value = varValue
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-08-23 18:03
ADODB.RecordsetにRecordCountというプロパティがあるみたいですが、
これで先に範囲書式指定しておけませんか?
SIC
会議室デビュー日: 2005/09/01
投稿数: 14
投稿日時: 2006-08-24 09:33
>まどかさん、mioさん
返答いただきありがとうございます。

2次元配列を使ったりレコードカウントと取得したりする方法は私も考えました。
実は最初の投稿のソースは質問の内容を理解してもらいやすくするために簡素化したもので、実際はエクセルでテンプレート的なファイルを作成してそこに貼り付けて印刷等を行う予定です。
2次元配列やレコードカウントを用いた場合改ページの処理がうまく行かず断念しました。
またデータ数2000件というのは今現在手元にあるテストデータの話でして、実際プログラムの納品先の使い方によっては10000件以上出力する場合や500件程度しか出力しない場合もあります。
説明不足で申し訳ありませんでした。

出来れば、エクセルのCopyが遅くなる原因を解消したいのですがうまい方法はないでしょうか?
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-08-24 11:05
引用:

SICさんの書き込み (2006-08-24 09:33) より:

実際はエクセルでテンプレート的なファイルを作成してそこに貼り付けて印刷等を行う予定です。


ということは、値のコピーだけで良いということでしょうか?
やはり、Range.Value で値を一気に貼り付けるという方法しか思いつきません。

引用:

2次元配列やレコードカウントを用いた場合改ページの処理がうまく行かず断念しました。


これは、同時にやろうとして、そう感じてしまったのではないでしょうか?
後から改ページの設定はできないような仕様なのでしょうか?

# グルーピングなどの関係であれば、何とでもできますけども...

引用:

出来れば、エクセルのCopyが遅くなる原因を解消したいのですがうまい方法はないでしょうか?


え? テンプレートがあると聞いた後なので、
Copy メソッドを使う必要がないように思っていたのですが...

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2006-08-24 11:36
引用:

SICさんの書き込み (2006-08-23 17:13) より:
VB6の質問です。
開発環境は
OS:WindowsXP SP2
Microsoft Office2000
言語:VB6 SP6
です。


直接の回答ではないのですが、DB の操作などは除いて、すべて Excel の VBA だけで書いたサンプルコードに直して、コピーの個所に関して、Excel の掲示板で質問されるのも手だと思います。
DB や VB が絡むよりも Excel の VBA 内で完結したほうが切り分けが楽になります。
また、結局は Excel というアプリケーションの仕様による部分が大きいので、情報量的には汎用の開発者向けの掲示板よりも Excel の掲示板のほうが情報の量が多いと思います。

私も、Excel 上の操作がなにかの拍子に妙に遅くなることがあって、原因が良く分からないことがありました。
ひとつの推測ですが、広い意味でのコピーなので Windows のクリップボードがなにか絡んでいるのかな?クリップボードをセキュリティー関連のソフトウェアが監視しているためかな?とも思うのですが良くは分かりません。とりあえず、Excel のバージョンは最新のサービスパックにして、セキュリティー関連のものは切ってみてはどうでしょうか。
また、ScreenUpdating などは設定されているようですが、Excel のウィンドウの大きさを故意に変えてみるなどしてはどうでしょうか。

--
unibon {B73D0144-CD2A-11DA-8E06-0050DA15BC86}
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2006-08-24 11:41
引用:

SICさんの書き込み (2006-08-24 09:33) より:
2次元配列やレコードカウントを用いた場合改ページの処理がうまく行かず断念しました。


コピーペーストでは、改ページ位置は狂いようがないと思いますが…。
それでもだめなら、やはり後から改ページ位置を修正するとか。

Excel VBAの高速化のポイントは、いかにロジックを作らずに組み込み関数を使うかと、いかに一回で大きな範囲を処理するか、だと思います。
プラスして、いかにワークシート側だけで処理を終えておくか、ですか。
SIC
会議室デビュー日: 2005/09/01
投稿数: 14
投稿日時: 2006-08-24 15:03
皆様、返答いただきありがとうございます。
またこちらの知識不足のため、お手数をおかけしまして申し訳ありません。

>じゃんぬねっとさん
テンプレートと言う言い方で誤解を与えてしまいすみません。
出力用のファイルに印刷する内容1ページ分のシートを用意しておき、
改ページの度にそれを貼り付けるという方法でやっていました。
なのでコピーの処理時間が問題となっています。

>unibonさん
セキュリティ関連ですか。そこまでは見ていませんでした。
急に遅くなったのでもしかしたらその可能性があるかも知れないので調べてみます。

>mioさん
改ページの位置ではなくて改ページのタイミングがうまく行きませんでした。
キーとなるフィールドの値が変わったらページの途中でも改ページをしたいので、
レコードカウントだけでは総ページ数が取得できなかったんです。
またキーとなるフィールドはユーザー側で変更できる仕様のため、
あらかじめ別のRecordsetで取得することも出来ませんでした。

まずはunibonさんが言われたセキュリティ絡みから調べてみて、
その上で出来る限りロジックを簡素化して対応してみようと思います。

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