質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

3回答

2548閲覧

ファイル容量自動取得VBA

jabe

総合スコア43

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2022/05/13 09:05

編集2022/06/14 01:36

実現したいこと

所定フォルダのファイル容量を取得し、Excelへ書込むプログラムの高速化をしたいと考えております。
お力添えをお願いします。

●現状
所定フォルダのファイル容量を取得し、Excelへ書込むプログラムを作成しました。
内容:フォルダのフルパスをVBAコードへ入力し、ボタン実行すると、Excelへ取得情報を書き込む
イメージ説明

発生している問題

プログラムは作成し動作はすのですが、以下問題が発生
ファイル数が200以上ある場合、処理に時間を要してしまいます。

該当のソースコード

VBA

1Private Sub btnAction_Click() 2 strPath = "C:\" '対象フォルダのフルパス入力 3 shtFile.Cells(8, 2) = " " 4 Range("A8", ActiveCell.SpecialCells(xlLastCell)).ClearContents 5 Range("A8").Select 6 i = 8 7 FileDisp strPath, i 8End Sub 9 10Private Sub FileDisp(strPath, i) 11 Set objFs = CreateObject("Scripting.FileSystemObject") 12 Set objFld = objFs.GetFolder(strPath) 13 For Each objFl In objFld.Files 14 shtFile.Cells(i, 2) = objFs.GetBaseName(objFl.Path) 15 shtFile.Cells(i, 3) = objFl.ParentFolder.Path 16 shtFile.Cells(i, 4) = Int(objFl.Size / 1024) 17 shtFile.Cells(i, 5) = objFl.Type 18 i = i + 1 19 Next 20 For Each objSub In objFld.SubFolders 21 FileDisp objSub.Path, i 22 Next 23 Range("J2") = Date 24 25End Sub 26

###追加△1
●以下フォルダパスで実行したところ、以下取得できないフォルダ、ファイルが発生してしまいました。1つのケースを抜粋させていただきます。
対象フォルダには、QR自動作成VBAフォルダ※格納ファイル:QRコード作成.xlsm
があるのですが、実行結果には記載されていませんでした。

●対象フォルダ:C:\Users\苗字\Desktop\名前\00_VBA※苗字、名前は自分の名前の為、伏せさせていただきます。
イメージ説明

●実行結果
イメージ説明
詳細
イメージ説明

###追加△2
回答者のhatena19さんのやり方をトライしたのですが、一部取得出来ない為改めて相談させていただきます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

Excel VBA の高速化の定番としては以下2点が挙げられます。

(1) 画面の描画を抑止する

処理開始時に Application.ScreenUpdating を False、終了時に True にします。

(2) 配列を使用する

VBA

1Dim va(1, 1) As Variant 2va(0, 0) = "A" 3va(0, 1) = 1 4va(1, 0) = "B" 5va(1, 1) = 2 6Range("A1:B2").Value = va

のような感じで複数のセルを一括で代入できます。

あとは細かいことですが

(3) Option Explicit を記述し、変数宣言を必須にする
(4) 変数や引数の型を明示する
(5) Microsoft Scripting Runtime を参照設定し、アーリーバインドする
(6) フォルダがネストしたとき Scripting.FileSystemObject が複数インスタンス化されるので、最初にインスタンス化し、引数で渡すかモジュール変数にしてしまう
(7) Range("J2") = Date が複数回実行される可能性がある
(8) ファイルサイズは Int だと桁数が不安なので CLng のほうが良いかも

といったところです。

投稿2022/05/13 11:25

編集2022/05/14 20:59
KOZ6.0

総合スコア2626

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jabe

2022/05/15 23:53

ご回答ありがとうございます。 高速化のポイントたくさんあるんですね、知らなかったです。 勉強してみます。
guest

0

高速化の対策は、KOZ6.0さんの回答で指摘されている通りです。

それをもとにコード化すると下記のような感じになるでしょう。

vba

1Option Explicit 2 3Private Sub btnAction_Click() 4 Application.ScreenUpdating = False 5 6 Dim strPath As String: strPath = "C:\Test" '対象フォルダのフルパス入力 7 Dim shtFile As Worksheet: Set shtFile = ActiveSheet 8 shtFile.Cells(8, 2) = " " 9 shtFile.Range("A8", ActiveCell.SpecialCells(xlLastCell)).ClearContents 10 11 Dim i As Long: i = 8 12 Dim objFs As New FileSystemObject 13 14 FileDisp objFs, strPath, i, shtFile 15 16 shtFile.Range("J2") = Date 17 Set objFs = Nothing 18 Application.ScreenUpdating = True 19End Sub 20 21Private Sub FileDisp(objFs As FileSystemObject, strPath As String, i As Long, shtFile As Worksheet) 22 Dim objFld As Folder: Set objFld = objFs.GetFolder(strPath) 23 24 Dim aryFl() 25 If objFld.Files.Count > 0 Then 26 ReDim aryFl(1 To objFld.Files.Count, 1 To 4) 27 Dim objFl As File, j As Long 28 For Each objFl In objFld.Files 29 j = j + 1 30 aryFl(j, 1) = objFs.GetBaseName(objFl.Path) 31 aryFl(j, 2) = objFl.ParentFolder.Path 32 aryFl(j, 3) = Int(objFl.Size / 1024) 33 aryFl(j, 4) = objFl.Type 34 Next 35 shtFile.Cells(i, 2).Resize(j, 4).Value = aryFl 36 End If 37 38 For Each objFld In objFld.SubFolders 39 FileDisp objFs, objFld.Path, i + j, shtFile 40 Next 41End Sub

VBAウィンドウの[ツール]→[参照設定]で
Microsoft Scripting Runtime
にチェックを入れておく。

ちなみに、Intは小数点以下を切り捨て、CLngは小数点以下を丸める、といった違いがあります。
Intの方がエラーなく表示できる桁数(Doubleの範囲まで)は大きいです。

投稿2022/05/14 07:25

編集2022/05/16 07:53
hatena19

総合スコア33715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOZ6.0

2022/05/14 20:58

Int はそうでしたか。失礼しました。
jabe

2022/05/15 23:57

ご回答とプログラム作成ありがとうございます。 早速プログラムを動作してみました。 以下エラーが発生してしまいました、原因分かりますでしょうか? 実行時エラー9※インデックスが有効範囲にありません。 結果を見てみますと、フォルダ一層目のデータは取得できていました。 2層目の一つのデータを取得し、止まる状況となっております。 よろしくお願いします。
hatena19

2022/05/16 01:16

エラーはどの行で発生しますか。 当方の環境では問題なく動作してます。
jabe

2022/05/16 04:50

連絡ありがとうございます。 そうなんですね。私の環境が問題の可能性があるんですかね? 以下コードでエラーが発生してしまいます。 Dim aryFl(): ReDim aryFl(1 To objFld.Files.Count, 1 To 4)
hatena19

2022/05/16 07:54

フォルダー内のファイル数が0のときにエラーになりますね。 回答のコードを対策したものに修正しましたのでそれを試してみてください。
jabe

2022/05/17 01:29

コード作成ありがとうございました。 問題なく動作しました。 助かりました。 コードの理解進めていきます。
jabe

2022/05/20 05:00

プログラム結果を確認したところ、一部のファイル情報を取得出来ていなかった事が分かりました。 プログラム自体はエラーなく動作しました。 原因分かりますでしょうか?
hatena19

2022/05/20 08:40

「一部のファイル情報を取得出来ていな」いものは何なのか、 どのような条件のときなのか、など、こちらで検証できる情報を提示してもらわないと、 原因特定は難しいです。
jabe

2022/05/22 10:47

ご連絡ありがとうございます。 事象を”追加△1”情報として質問文に追加させていただきました。 ご協力のほどよろしくお願いします。
jabe

2022/05/30 05:26

hatena19さん、上記内容いかがでしょうか?
guest

0

フォルダのファイル容量を求めるってのは、フォルダの中にあるファイルのファイルサイズをそれぞれ合計していくために時間がかかります。
まあ、そういうもん、とおもっておきましょう

投稿2022/05/13 10:03

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/05/13 15:10

たかだか 200 のファイルでそんなわけないでしょう。 > Set objFs = CreateObject("Scripting.FileSystemObject") これを毎回やってるのと、処理のたびにセルを一つづついじってるのがパッと見て目につきます。 これらを改善するだけでかなり変わると思いますが。
jabe

2022/05/16 00:00

ご回答ありがとうございます。 セルを1つずつ見ている為、対象フォルダのデータ数が多いと速度に影響しているって事でしょうか。 Set objFs = CreateObject("Scripting.FileSystemObject") こちら、解消する方法は分かりますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問