'--- サブフォルダのパス一覧を配列に取得する ---'
Public Sub GetAllSubFolderPath()
'--- フォルダ一覧を取得したいフォルダのパス ---'
Dim folderPath As String
folderPath = "[フォルダパス]"
'--- フォルダパスを取得する ---
Dim folderList As Variant
folderList = GetFolderPath(folderPath)
End Sub
'--- サブフォルダを再帰的に取得する関数 ---'
Public Function GetFolderPath(folderPath As String) As String()
'--- ファイルシステムオブジェクト ---'
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
'--- フォルダ数を格納する変数 ---'
Dim n As Variant
n = fso.GetFolder(folderPath).SubFolders.Count
Dim r As Long
Dim c As Long
Application.ScreenUpdating = False
For r = 1 To UBound(folderList)
fs = Split(Mid(folderList(r), Len(folderPath)), "\")
For c = 1 To UBound(fs)
Cells(r, c + 1).Value = fs(c)
Next
Next
Application.ScreenUpdating = True
If (0 < n) Then
'--- フォルダパスを格納する配列 ---'
Dim str() As String
ReDim str(1 To n)
'--- フォルダパスを格納 ---'
Dim i As Long
Dim j As Long
Dim m As Long
i = 1
Dim strTmp() As String
'フォルダパスを指定してすべてのサブフォルダを取得
Dim f As Object
For Each f In fso.GetFolder(folderPath).SubFolders
str(i) = f.Path
strTmp = GetFolderPath(str(i)) '再帰的呼び出し
If (Not IsEmptyArray(strTmp)) Then
m = UBound(strTmp, 1)
Else
m = 0
End If
'サブフォルダ内にさらにフォルダがあればその分だけ配列を拡張
n = UBound(str, 1)
ReDim Preserve str(1 To n + m)
For j = 1 To m
str(i + j) = strTmp(j)
Next j
i = i + m + 1
Next f
End If
GetFolderPath = str
End Function
'--- 配列が空かどうかを判定する関数 ---'
Public Function IsEmptyArray(arrayTmp As Variant) As Boolean
On Error GoTo ERROR_
If (0 < UBound(arrayTmp, 1)) Then
IsEmptyArray = False
End If
Exit Function
ERROR_:
IsEmptyArray = True
End Function
1Option Explicit
234' 起点フォルダを記載するセル
5Private Const CELL_BASE_FOLDER As String = "B2"
678' -------------------------------------------
9' フォルダ一覧作成
10' -------------------------------------------
11' ---- 起動: フォルダ一覧作成
12Sub get_folder_list()
13 ' 起点とするフォルダを選択
14 Dim base_folder_path As String
15 base_folder_path = folder_pick("作成するフォルダ一覧の対象フォルダを指定してください。")
1617 ' フォルダが指定された場合処理開始
18 If base_folder_path <> "" Then
1920 ' サブフォルダを再帰的に一覧取得
21 Dim fso As Object
22 Set fso = CreateObject("Scripting.FileSystemObject")
2324 Dim folder_list As Variant ' サブフォルダリスト(配列)
25 get_sub_folders fso.GetFolder(base_folder_path), folder_list
26 Set fso = Nothing
2728 ' シートに転記
29 write_folder_list ActiveWorkbook.ActiveSheet, base_folder_path, folder_list
30 Else
31 ' フォルダ指定しなかった場合の動作
32 End If
33End Sub
3435' ---- 再帰的にサブフォルダを検索
36' TARGET: 検索対象のフォルダオブジェクト
37' arr: フォルダリスト配列(参照渡し)
38Private Sub get_sub_folders(TARGET As Object, ByRef arr As Variant)
39 Dim sub_folder As Object
4041 For Each sub_folder In TARGET.SubFolders
42 push_arr sub_folder.PATH, arr
43 get_sub_folders sub_folder, arr
44 Next
45End Sub
4647' ---- シートにフォルダリストを出力
48' ws: 出力するシート
49' base_folder_path: ベースフォルダ
50' folder_list: フォルダリスト配列
51Private Sub write_folder_list(ws As Worksheet, base_folder_path As String, folder_list As Variant)
52 Dim i As Long
53 Dim j As Long
54 Dim path_array As Variant
5556 ' 起点とするセル
57 With ws.Range(CELL_BASE_FOLDER)
58 ' ベースとしたフォルダをそのセルに記載
59 .Value = base_folder_path
6061 ' 以下ループしながらセルに出力(offset で起点セルからの相対位置をずらしながら出力)
62 For i = LBound(folder_list) To UBound(folder_list)
6364 ' 配列要素からベースフォルダ部分を削除し、残りを \ で分割して配列化
65 path_array = Empty
66 path_array = Split(Replace(folder_list(i), base_folder_path & "\", ""), "\")
6768 ' 念のために配列化されているかをチェック
69 If IsArray(path_array) Then
70 ' セルに記載
71 .Offset(i - LBound(folder_list) + 1, 0).Value = base_folder_path
72 For j = LBound(path_array) To UBound(path_array)
73 .Offset(i - LBound(folder_list) + 1, j - LBound(path_array) + 1).Value = path_array(j)
74 Next
75 End If
76 Next
77 End With
7879 Set ws = Nothing
80End Sub
81828384' -------------------------------------------
85' フォルダ作成
86' -------------------------------------------
87' ---- 起動: フォルダ作成
88Sub create_folders()
8990 ' 元とするシート
91 Dim ws As Worksheet
92 Set ws = ActiveWorkbook.ActiveSheet
9394 ' 作成先のフォルダを取得
95 Dim dest_folder_path As String
96 dest_folder_path = folder_pick("サブフォルダを作成するフォルダを指定してください。")
9798 ' 作成先のフォルダを指定された場合
99 If dest_folder_path <> "" Then
100 Dim fso As Object
101 Set fso = CreateObject("Scripting.FileSystemObject")
102103 ' 指定したフォルダ内が空でない場合は念のため終了
104 If Dir(fso.BuildPath(dest_folder_path, "*")) <> "" Then
105 MsgBox "指定したフォルダ内が空ではないようです。安全のため処理を中止します。", vbOKOnly, "中止"
106 Exit Sub
107 End If
108109 ' サブフォルダ作成
110 ' =================================================
111 ' Excelのシートからデータ取得
112 With ws.Range(CELL_BASE_FOLDER)
113 Dim target_path As String
114 Dim i As Long ' 相対行に相当
115 Dim j As Long ' 相対列に相当
116117 ' 行の初め(フォルダ一覧を作成した際の検索基点フォルダ名が入っているはず)が空になるまで行方向にループ
118 i = 1
119 Do Until .Offset(i, 0).Value = ""
120 ' フォルダ作成する基点フォルダパスを設定
121 target_path = dest_folder_path
122123 ' 列(=フォルダ階層)がなくなるまで列方向にループ
124 ' 列の上位からたどっているため、パスを追記しながらフォルダの存在をチェックしなければ作る、を繰り返す
125 j = 1
126 Do Until .Offset(i, j).Value = ""
127 target_path = fso.BuildPath(target_path, .Offset(i, j).Value)
128 If Not (fso.FolderExists(target_path)) Then MkDir target_path
129 j = j + 1
130 Loop
131 i = i + 1
132 Loop
133 End With
134135 Set fso = Nothing
136 Set ws = Nothing
137 Else
138 ' フォルダ指定をキャンセルした場合の処理
139 End If
140End Sub
141142143144145' -------------------------------------------
146' 共通関数
147' -------------------------------------------
148149' ---- フォルダ選択ダイアログ
150Private Function folder_pick(Optional dialog_title As String = "") As String
151 Dim tmpRet As String
152153 With Application.FileDialog(msoFileDialogFolderPicker)
154 .AllowMultiSelect = False
155 If dialog_title <> "" Then .Title = dialog_title
156 If .Show = True Then
157 tmpRet = .SelectedItems(1)
158 Else
159 tmpRet = ""
160 MsgBox "処理を中止しました。", vbOKOnly, "中止"
161 End If
162 End With
163164 folder_pick = tmpRet
165End Function
166167168' ---- 配列の最後にデータ追加
169Private Sub push_arr(DATA As Variant, ByRef arr As Variant)
170171 If IsArray(arr) Then
172 ReDim Preserve arr(UBound(arr) + 1)
173 Else
174 ReDim arr(0)
175 End If
176177 ' 配列に代入
178 If IsObject(DATA) Then ' データがオブジェクトの場合
179 Set arr(UBound(arr)) = DATA
180 Else ' データがオブジェクトではない場合
181 arr(UBound(arr)) = DATA
182 End If
183End Sub
184
コメントありがとうございます。
私が教えて頂いたコードを挿入する場所を間違えているのだと思います
Dim As Stringでは「配列がありません」とエラーになりましたので
私はVariantにしました。
0
ベストアンサー
こんな感じですかねぇ。
GetFolderPathの下に入れてください。
VBA
1Dim r As Long
2Dim c As Long
3Application.ScreenUpdating = False
4For r = 1 To UBound(folderList)
5 fs = Split(Mid(folderList(r), Len(folderPath)), "\")
6 For c = 1 To UBound(fs)
7 Cells(r, c + 1).Value = fs(c)
8 Next
9Next
10Application.ScreenUpdating = True
上の処理はベタに処理しているので件数が多いと結構遅いです。
以下は配列化して高速化したものです。
VBA
1Dim r As Long
2Dim c As Long
3ReDim tmp(UBound(folderList), 1) As Variant
4Application.ScreenUpdating = False
5For r = 1 To UBound(folderList)
6 fs = Split(Mid(folderList(r), Len(folderPath) + 1), "\")
7 If UBound(fs) > UBound(tmp, 2) Then
8 ReDim Preserve tmp(UBound(tmp, 1), UBound(fs))
9 End If
10 For c = 0 To UBound(fs)
11 tmp(r - 1, c) = fs(c)
12 Next
13Next
14Range("B1").Resize(UBound(tmp, 1), UBound(tmp, 2)) = tmp
15Application.ScreenUpdating = True
16
コメントありがとうございます。
少し教えて頂けないでしょうか?
Dim n As Variant
n = fso.GetFolder(folderPath).SubFolders.Count
の後に教えて頂いた構文を追加いたしました。
fsの定義をLongにして実行したら、UBoundの配列がありませんとなってしまいました
ご指導いただけないでしょうか
宜しくお願いいたします。
入れてるところが違いますね。
GetAllSubFolderPath関数でGetFolderPath関数を呼んでいる下の行に入れてください。
'--- フォルダパスを取得する ---
Dim folderList As Variant
folderList = GetFolderPath(folderPath)
ここに入れる
End Sub
補足
GetFolderPath関数でフォルダのリストが取得できているのは確認されているでしょう。
その関数の戻り値folderListを使ってシートに展開するという流れです。