再帰処理とは?指定フォルダ内のサブフォルダ全てをフォルダ構成のみ(空フォルダ)を別フォルダにコピー(Excel VBA)

先日お話ししました

指定フォルダ内のサブフォルダ全てをフォルダ構成のみ(空フォルダ)を別フォルダにコピー(Excel VBA)

の中で、どのようにフォルダの処理を移動していったかをご説明いたします。

■コピー元

今回作成したプロシージャ

今回作成したプロシージャは下記の通りです。

Sub 指定したフォルダ内のサブフォルダ全て空にしてコピー()  '・・・①
'アクティブシートからコピー元のフォルダパスを取得(pt_m)
'アクティブシートからコピー先のフォルダパスを取得(pt_s)
'コピー先フォルダを新規作成(pt_s)
'コピー元のフォルダ(pt_m)のサブフォルダ全てを空の状態でコピー先のフォルダ(pt_s)へコピー
    '【変数】
    Dim ws As Worksheet  '処理対象シート
    Dim pt_m As String   'コピー元フォルダパス
    Dim pt_s As String   'コピー先フォルダパス
    Dim fd_len As Long   'コピー元フォルダ文字数
    
    Application.ScreenUpdating = False '画面表示の停止
    
    '■変数セット
    Set ws = ActiveSheet    '変数ws=アクティブシートをセット
    pt_m = ws.Range("A3")   '変数pt_mにセルA3のコピー元フォルダパスをセット
    pt_s = ws.Range("A6")   '変数pt_sにセルA6のコピー先フォルダパスをセット
    fd_len = Len(pt_m)      'コピー元フォルダ文字数
    
    '■コピー元フォルダ存在確認
    If Dir(pt_m, vbDirectory) = "" Then
        MsgBox "ご指定のコピー元フォルダは存在しません。"
        Exit Sub
    End If
    
    '■コピー先最上位フォルダ存在確認
    If Dir(pt_s, vbDirectory) <> "" Then
        MsgBox "ご指定のコピー先フォルダは既に存在します。"
        Exit Sub
    End If
    
    '■コピー先最上位フォルダ作成
    MkDir pt_s
    
    '■コピー元フォルダのサブフォルダをコピー先フォルダにコピー
    Call サブフォルダコピー(pt_m, pt_s, fd_len)  '・・・②
 
    Application.ScreenUpdating = True '画面表示の再開
    
End Sub  '・・・⑥

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long)  '・・・③
    '【変数】
    Dim FSO As Object       'FileSystemObject
    Dim m_fd As Object   'メインフォルダ
    Dim s_fd As Object    'サブフォルダ
    Dim pt_sub As String    'サブフォルダパス
    
    '■変数セット
    Set FSO = CreateObject("Scripting.FileSystemObject")   'FileSystemObjectのインスタンス化
    Set m_fd = FSO.GetFolder(pt_m) 'コピー元フォルダの親フォルダ
    
    '■コピー元フォルダの親フォルダのサブフォルダを順に処理
    For Each s_fd In m_fd.SubFolders
    
        pt_sub = s_fd.Path 'サブフォルダのパス
        
        '■コピー先フォルダにサブフォルダ構造をコピー
        MkDir pt_s & Mid(pt_sub, fd_len + 1) 'サブフォルダのフルパスから、親フォルダのパスを除いた部分を抽出
        
        '■再帰処理:処理中のpt_subを親フォルダとして、サブフォルダを処理していく。
        Call サブフォルダコピー(pt_sub, pt_s, fd_len)  '・・・④
    Next s_fd
    
    Set FSO = Nothing 'FSOを空っぽにする
    
End Sub  '・・・⑤

「再帰処理」を使った処理順

今回の処理で、コピー元として指定しているのは「C:\VBA\第1階層」という一番上の階層のパスのみ。

それなのに、サブフォルダ全てのフォルダ名を読み込みにいっています。

それらのことを可能にしているのが「再帰処理」なのです。

再帰処理」とは、1つのプロシージャが終了していない途中で「自分自身」を呼び出す処理のことなのです。

上記処理でいうと

Sub 指定したフォルダ内のサブフォルダ全て空にしてコピー() ‘・・・①

Call サブフォルダコピー(pt_m, pt_s, fd_len) ‘・・・②

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④



といった具合に、「 For Each s_fd In m_fd.SubFolders」で受け取ったサブフォルダ「s_fd 」が無くなるまでフォルダパスを変更しながら、「自分自身」の処理を繰り返すのです。

フォルダの処理順

今回のフォルダの処理順は下記の通りです。
フォルダ図の丸番号と下記「プロシージャ内の処理順と処理対象フォルダのパス」の丸番号の意味は異なります。

プロシージャ内の処理順と処理対象フォルダのパス

「↓↓↓」は、処理対象フォルダのパスです。
」はフォルダ作成処理です。
文中の丸番号は、上記プロシージャに記載している丸番号のことです。

Sub 指定したフォルダ内のサブフォルダ全て空にしてコピー() ‘・・・①

C:\VBA\第1階層_NEWを作成

Call サブフォルダコピー(pt_m, pt_s, fd_len) ‘・・・②
↓↓↓ 「pt_m」→C:\VBA\第1階層→「pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層_NEW\第2階層1を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓「pt_sub」→C:\VBA\第1階層\第2階層1→pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層_NEW\第2階層1\第3階層1-1を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓「pt_sub」→C:\VBA\第1階層\第2階層1\第3階層1-1→pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層\第2階層1\第3階層1-1 にサブフォルダが無いためフォルダ作成処理無し
↓↓↓「第3階層1-1」以下にサブフォルダが無いため For Each を抜ける

End Sub ‘・・・⑤
↓↓↓ 「pt_m」→C\VBA\第1階層\第2階層1(ひとつ前の処理の For Each に戻る)
C:\VBA\第1階層_NEW\第2階層1\第3階層1-2を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓「pt_sub」→C:\VBA\第1階層\第2階層1\第3階層1-2→pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層\第2階層1\第3階層1-2にサブフォルダが無いためフォルダ作成処理無し
↓↓↓「第3階層1-2」以下にサブフォルダが無いため For Each を抜ける

End Sub ‘・・・⑤
↓↓↓ 「pt_m」→C\VBA\第1階層\第2階層1(ひとつ前の処理の For Each に戻る)
C:\VBA\第1階層_NEW\第2階層1\第3階層1-3を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓「pt_sub」→C:\VBA\第1階層\第2階層1\第3階層1-3→pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層\第2階層1\第3階層1-3にサブフォルダが無いためフォルダ作成処理無し
↓↓↓「第3階層1-3」以下にサブフォルダが無いため For Each を抜ける

End Sub・・・⑤
↓↓↓「pt_m」→C:\VBA\第1階層\第2階層1(ひとつ前の処理の For Each に戻る)

End Sub・・・⑤
↓↓↓ 「pt_m」→C:\VBA\第1階層(ひとつ前の処理の For Each に戻る)
C:\VBA\第1階層_NEW\第2階層2 を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓「pt_sub」→C:\VBA\第1階層\第2階層2→pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層\第2階層2 内にサブフォルダが無いためフォルダ作成処理無し
↓↓↓「第2階層2以下にサブフォルダが無いため For Each を抜ける

End Sub ‘・・・⑤
↓↓↓ 「pt_m」→C:\VBA\第1階層(ひとつ前の処理の For Each に戻る)
C:\VBA\第1階層_NEW\第2階層3を作成

Call サブフォルダコピー(pt_sub, pt_s, fd_len) ‘・・・④
↓↓↓ 「pt_sub」→C:\VBA\第1階層\第2階層3pt_m」として受け取り

Sub サブフォルダコピー(pt_m As Variant, pt_s As Variant, fd_len As Long) ‘・・・③
C:\VBA\第1階層\第2階層3 内にサブフォルダが無いためフォルダ作成処理無し
↓↓↓「第2階層3以下にサブフォルダが無いため For Each を抜ける

End Sub ‘・・・⑤
↓↓↓ 「pt_m」→C:\VBA\第1階層(ひとつ前の処理の For Each に戻る)

End Sub ‘・・・⑤

End Sub ‘・・・⑥

長い道のりでしたね。

【参考】

指定したフォルダ内のファイル名全てを取得(Excel VBA)
変数でよく使われる「buf」「tmp」の意味
Dir関数が取得するファイルの順番
指定したフォルダ内のフォルダ名全てをGetAttrを使って「エラー53 ファイルが見つかりません。」を出さずに取得(Excel VBA)
GetAttrとは?「= vbDirectory」ではなく「And vbDirectory」となるビット演算の疑問
フォルダ名だけを取得したい時に出てくる 「.」 と 「..」 とは?
指定したフォルダ内とサブフォルダ内全てのファイル名を取得(Excel VBA)
CreateObject(“Scripting.FileSystemObject”) を使ってサブフォルダを取得
再帰処理とは?フォルダ内とサブフォルダ内全てのファイル名を取得(Excel VBA)
指定したフォルダ内のサブフォルダのフォルダ名を全部取得(Excel VBA)
再帰処理とは?フォルダ内のサブフォルダのフォルダ名を全部取得(Excel VBA)
参照渡し「ByRef」と値渡し「ByVal」の違い(Excel VBA)
ファイルのフルパスからファイル名のみを取得 InStrRev関数(Excel VBA)
指定したフォルダの全ての階層のフォルダ名・サブフォルダ名・ファイル名を取得(Excel VBA)
FileSystemObjectとは?CreateObject 関数 FolderExists・GetFolderの使い方
FileSystemObject CreateObject関数を使う方法・ 参照設定を使う方法 違いを理解してエラー防止
再帰処理とは?指定したフォルダの全ての階層のフォルダ名・サブフォルダ名・ファイル名を取得(Excel VBA)
ファイルのフルパスからファイル名のみを取得 Split関数(Excel VBA)
Callステートメントとは 引数 括弧()の使い方(Excel VBA)
指定したフォルダ内から「特定の文字を含まないファイル名」を取得(Excel VBA)
ワイルドカードとは。使い方いろいろ。(Excel)
Dir関数の使い方。ファイル名やフォルダ名の取得方法。(Excel VBA)
指定したフォルダのファイル名を取得し、そのファイル名を一括で変換(Excel VBA)
Excel起動時に「コンパイルエラー」。64ビット システムで Declareステートメントに、PtrSafe属性を設定(Excel VBA )
「ファイルを開く」ダイアログボックス から ファイル名を取得(Excel VBA)
「ファイルを開く」ダイアログボックス から 複数 ファイル名を取得(Excel VBA)
指定フォルダ内のサブフォルダ全てをフォルダ構成のみ(空フォルダ)を別フォルダにコピー(Excel VBA)
再帰処理とは?指定フォルダ内のサブフォルダ全てをフォルダ構成のみ(空フォルダ)を別フォルダにコピー(Excel VBA)

■■■スポンサーリンク■■■