VBA100本ノック 89本目を動画で解説しています。Excelの神髄さんの模範解答はコチラ
問題
#VBA100本ノック 89本目
フォルダ「A」とフォルダ「B」を統合して、
フォルダ「C」を作成する。
全サブフォルダの、全ファイルを対象としてください。
同一フォルダに同一ファイル名となる場合は、
より更新日時の新しいファイルを採用してください。
同一更新日時の場合はどちらでも良い。
※パスは任意で
解答
Sub ノック89本目()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim sPathA As String: sPathA = wb.Path & "\A"
Dim sPathB As String: sPathB = wb.Path & "\B"
Dim sPathC As String: sPathC = wb.Path & "\C"
Dim objFSO As New FileSystemObject
If objFSO.FolderExists(sPathC) Then
objFSO.DeleteFolder sPathC 'Cフォルダがあれば削除
End If
objFSO.CopyFolder sPathA, sPathC 'とりあえずAをCの名前で複製
Call 再帰(sPathB, sPathB, sPathC, objFSO) '元ファイル名,fsoを渡しつつ呼び出し
End Sub
Sub 再帰(元F名 As String, 元々BFol名 As String, 元々CFol名 As String, objFSO As FileSystemObject)
'Cフォルダに元Fol名のフォルダが無ければフォルダごとコピー
Dim F名チェック用 As String
F名チェック用 = Replace(元F名, 元々BFol名, 元々CFol名)
If Not objFSO.FolderExists(F名チェック用) Then
objFSO.CopyFolder 元F名, F名チェック用 'もし無ければコピー。
Exit Sub 'それ以下のフォルダは再帰しない
End If
'Cフォルダに元のファイル名と同名のファイル無ければコピー。あれば更新時刻を比較
Dim f As File, File名チェック用 As String
For Each f In objFSO.GetFolder(元F名).Files
File名チェック用 = F名チェック用 & "\" & f.Name
If Not objFSO.FileExists(Fileチェック用) Then 'もし同名のファイルがなければ
objFSO.CopyFile 元F名 & "\" & f.Name, Fileチェック用 'ファイルをコピー
Else
If f.DateLastModified >= objFSO.GetFile(Fileチェック用).DateLastModified Then 'Bの更新が新しければ
objFSO.CopyFile 元F名 & "\" & f.Name, Fileチェック用 'ファイルをコピー
End If
End If
Next
'サブフォルダを再帰呼び出し
Dim 元Fol As Folder
For Each 元Fol In objFSO.GetFolder(元F名).SubFolders
Call 再帰(元Fol.Path, 元々BFol名, 元々CFol名, objFSO)
Next
End Sub
■考え方・流れ
0:00 冒頭・問題確認
2:12 変数の宣言、コードの流れを考察
4:56 再帰用のプロシージャ作成
6:28 再帰のコード考察
8:27 コピー先にフォルダがなければフォルダごとコピー
12:11 更新時刻が新しいか、コピー先にフォルダがなければコピーする
今回も投稿主の語彙力と説明力のなさが光っております!

89本やってきてこれは
ヤバいですね!

煽りツイートやめて?

確かに煽りはよくない…
変数の宣言、コードの流れを考察
66本目の再帰のコードを引用して使っていきます!

ファイルコピー、フォルダコピーなども66本目で使った
FSOさんをそのまま使用!
変数名はobjFSO。

考え方はこんな感じ。

1.”C”フォルダがあれば削除。
2.”A”フォルダをコピーして”C”フォルダに名前変更。
3.”B”ファルダを再帰してコピーしていく。

フォルダの削除はfsoのDeleteFileメソッドさん!

フォルダのコピーはCopyFolderメソッドさんを使えば簡単!

この辺りがわからないという方は、ノック20本目を見返してね!
再帰用のプロシージャ作成
※一旦、引数でフォルダを受け渡すようにしてます。
この後で思い返し、フォルダ名(String)を受け渡した方が簡単ということに気づきましたww

別プロシージャの呼び出しは、Callステートメントさんを使えば良かったね!

ついでに、FSOさんも引数で受け渡しちゃいましょう!

こんな感じ!
これでSub 再帰でもFSOさんが使えるね!


ここまでは大丈夫かな?
再帰のコード考察
再帰の考え方に入っていきましょう!
だけど…考えれば考えるほど…「フォルダ」じゃなくて「フォルダ名」を
受け渡す方がいいことに気づく…ww
許して下せえ!


再帰は66本目でやったように、For Eachさんを使います。
受け取ったフォルダの中の、サブフォルダを回していくイメージ!


一旦はここまで!
コピー先にフォルダがなければフォルダごとコピー
ココからは少し、処理速度とかを鑑みて、
不要な処理はしないようにしていくよー!
コピー先に、引数で受け取ったフォルダ名のフォルダがなければ、フォルダごとコピーすればええやん。
いちいちそのフォルダの中のサブフォルダを再帰…とかってしなくてええやん。
大元のフォルダをコピーすればええんやから。って話。

まずはコメントから書いていくといいかも…

フォルダがあるかどうかを判定したいから…

元々はフォルダ”A”だった部分を、新しい”C”に置換してあげて比較!

ムズすぎて吐きそう…

更新時刻が新しいか、コピー先にフォルダがなければコピーする
最後は同名のフォルダがあった場合、それぞれの中身のファイルの更新時刻を判定!

ファイルの更新時刻を調べたい場合は、FSOさんのFileExistsを使えばいいね!

デカかった方を残せばOK

こ、これで完成かな…

ホントにお疲れさまでござんした…

お疲れ様!
ポケモン発売だね!

急に何すか!
あとがたり
おはこんばんちは。uぷ主です。
89本目、二つのフォルダを統合する問題でした…
いや~、再帰、また来ちゃったか~!って感じでした…w
頭がおかしくなりそうになります。
でも実は…LAMBDA関数が出てから…
pythonでちょこっと勉強したのでw
ある程度やりたいことはできるようになってきたかな!
フォルダとか、階層チックな構造の処理をするときには
知ってて損はないですよね。
再帰を知るまでは、とりあえずエラー処理入れて、
1から100フォルダ分ループして…みたいにやったことありましたが…
処理に意味わからんぐらい時間かかってたもんなぁ…
いや~、ちゃんと学ぶって大事w
今回も超勉強になりました。
ありがとうございました。
あ、そうそう、いよいよポケモンSV発売されましたね。
ちょっと最近、本業が忙しいんで…まだ買えてないんですが…
買います。そのうち。
スカーレットかな~!
全国のExcelとポケモン好きのみなさん、ぜひ友達になって下さい!
以上!
最後までご視聴いただいたみなさん!ありがとうございました!
コメント