スポンサーリンク
はじめに
PCで共有サーバ等の中に、やたら深いフォルダの階層構造が作られていることがある。
下図みたいな感じとかね。
で、それらフォルダの中にはExcelなどファイルもたくさん保存されているけど、それらファイルは避けてフォルダだけを、コピー作成したいってことがある。
もちろん、忠実に最深部階層まで、構造を再現して全部コピーするのね。
まあそんな機会なんて、実際そう多くはないだろうけどね。
で今回はその、ファイルは避けてフォルダ構造だけをコピーするExcelマクロを書いてみる。
というか、Excelマクロでこんなフォルダ構造がどうこうとか言ったら、フォルダ構造とかファイル名とかをExcelシートに書き出すマクロが、ググれば山ほど見つかる。
私もそういうマクロは自分で作ってるし、その際にはファイル名とかだけじゃなく最終更新時刻とか多くの要素を組み込んでるけどね。
で、今回のマクロがフォルダ構造だけをコピーするものだというのは、それら既存のマクロとは敢えて視点を変えてみたもの。
最近、私が自分の経理課の共有サーバ使うに当たって、こういうマクロがほしいと思ったんで即興で書いたものです。
実際のところフォルダ構造なんて、あんまり深くするものじゃなくて3階層以内とかにすべきなんだけどね。
ちょっとうちの経理課のフォルダ階層は深すぎる。
そのせいもあって、共有サーバがイマイチ有効活用されていないんだよね。
マクロの動作要件等
FileSystemObject
今回は、フォルダを分析しまくるマクロなので、FileSystemObjectというやつを使う。
そのためには「Microsoft Scripting Runtime」の参照設定をしておく必要がある。
それについては、個人用マクロブックの設定の記事に書いといたので、そちらをどうぞ。
固定フォルダを指定する
今回のマクロは、
C:\tmp
という固定フォルダの中に、現在時刻のフォルダを新規作成する前提としている。
私はあまり、こういう風にフォルダをマクロ中で固定指定するのは好きじゃなくてユーザに自由選択させたいんだけど、今回のマクロをスムーズに動かすためにはこれがしっくり来た。
だから、
C:\tmp
というフォルダを使うのが嫌だったら、ソースコード中にこのフォルダパスが1箇所だけ書いてるから、そこを好きに書き換えて下さい。
動作
で、マクロを起動すると、フォルダ構造をコピーしたい親フォルダを指定するダイアログが出てくるので、そこで親フォルダを指定する。
(親フォルダとかなんか言葉が色々と小難しいかもしれんが、実際に適当に動かせばなんとかなるんで)
で、固定フォルダの中に「2019年01月18日06時30分40秒」みたいな現在時刻のフォルダが作成され、その中にフォルダの階層構造がコピーされる。
ただ、そのフォルダ指定ダイアログで、「Cドライブの中身まるごと」みたいな広範囲過ぎる指定はしないでね。
アクセス権限がどうこう問われ、「書き込みできません。」なんてエラーが出ちゃうんで。
めんどいから、このエラー対策も特に盛り込みません。
マクロのソースコード
それでは今回のマクロのソースコード。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
Dim lenMainFolder As Long Dim strNewFolder As String Sub setMainFolder() '大元のメインフォルダを設定し、再帰処理マクロを呼び出す Dim strMainFolder As Variant With Application.FileDialog(msoFileDialogFolderPicker) If Not .Show Then Exit Sub strMainFolder = .SelectedItems(1) & "\" End With Application.ScreenUpdating = False '描画を省略 '大元のメインフォルダのパスについて、文字数を取得しておく。 '次のcopySubFoldersプロシージャで使用。 lenMainFolder = Len(strMainFolder) '現在時刻のフォルダを新規作成する strNewFolder = "C:\tmp\" & Format(Now, "yyyy年mm月dd日hh時mm分ss秒") MkDir strNewFolder 'フォルダ作成 Call copySubFolders(strMainFolder) '再帰処理によるサブフォルダ分析 Application.ScreenUpdating = True '描画再開 Shell "C:\Windows\Explorer.exe " & strNewFolder, vbNormalFocus '最後にフォルダを開く End Sub Sub copySubFolders(strMainFolder As Variant) '再帰処理によるサブフォルダ分析 Dim FSO As New FileSystemObject Dim objMainFolder As Folder Set objMainFolder = FSO.GetFolder(strMainFolder) '親フォルダ Dim subPath As Variant Dim objSubFolder As Folder For Each objSubFolder In objMainFolder.SubFolders subPath = objSubFolder.Path 'サブフォルダのフルパス '現在時刻フォルダ(strNewFolder)の中にサブフォルダ構造をコピーする 'Mid(subPath, lenMainFolder)で、サブフォルダのフルパスから、親フォルダのパスを除いた部分を抽出 MkDir strNewFolder & Mid(subPath, lenMainFolder) '再帰処理。現在処理しているsubPathを今度は親フォルダとして、サブフォルダを辿っていく。 Call copySubFolders(subPath) Next objSubFolder End Sub |
この「setMainFolder」マクロをExcelの個人用マクロブックに組み込んで使うと良いだろう。
それでは余計なお世話で、ちょっとソースコードの解説を。
モジュールレベル変数
マクロで使用する変数っていうのは普通、Sub で始まりEnd Subで終わるプロシージャという固まりの中に入れて書き込む。
でも今回は、ソースコードの先頭にいきなり
Dim strNewFolder As String
と2つの変数を宣言してて、これらをSub~End Subのプロシージャの中には入れてない。
こういう風に、プロシージャの中に入れない変数を、モジュールレベル変数とか言うんだけどね。
今回はプロシージャを「setMainFolder」「copySubFolders」と2つ用意してて、どうしてもそれらで共通に使いたい変数を、このモジュールレベル変数にしてみた。
要するにモジュールレベル変数っていうのは、そうやって複数プロシージャで共通利用できる、利用範囲が広い設定の変数ってこと。
更に利用範囲の広いものとしてはパブリック変数なんてのもあるけど、これは割と手間がかかる規模のマクロで使うものだから、ここでは述べない。
で、モジュールレベル変数にしても、やたらめったら使うもんじゃないし、私も極力使わないようにしてるんだけどね。
今回は、次に述べる再帰処理ってやつも絡むから、モジュールレベル変数を使った方が分かりやすくなると判断した。
再帰処理
今回、「copySubFolders」プロシージャの中で、
Call copySubFolders
と、自分で自分をCallするような処理を書いている。
これが、再帰処理とか言われるやつで、サブフォルダを検索したらそのまたサブフォルダに、・・・というように構造を潜っていくのに使用している。
この再帰処理って、フォルダ構造を分析するのには必ず紹介される定番テクニックだ。
しかし逆に言うと、フォルダ構造の分析以外でこれを使ったマクロって、ちょっと見たことがない。
だから、フォルダ構造に関する非常に限定された場合のテクだと、片隅にとどめておく程度で良い。
私も普段は全然こんなの使わないけど、今回即興で何も見ずマクロを書いてみたら、意外と上手くいった。
その他
今回のマクロは、処理終了後に、作成した現在時刻のフォルダを自動的に開くようにしている。
Shell “C:\Windows\Explorer.exe ” & strNewFolder, vbNormalFocus ‘最後にフォルダを開く
ってやつがそれで、別記事でこれは個別に取り上げている。
スポンサーリンク