[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『空フォルダの削除方法でより効率的な方法ないですか』(すけろく)
自社サーバー内のフォルダ整理をしています。
その過程の中で空フォルダがあれば削除をするのですが、
あまりに数が多く(全体で1億フォルダほど)、手作業では
無理と判断し、VBAでコードを組みました。
消すこと自体はなんとかできているのですが、For-NextやDo-Loopで
ぐるぐるまわしていることもあり、かなりの時間を要しています。
より効率的な(作業時間を短縮できるような)方法がありましたら
ご教示いただけますと助かります。
現在のおおまかなロジックは
1.基本となるフォルダを指定
2.再帰処理でフォルダ内にサブフォルダやファイルの無いフォルダを
リスト化
3.2のリストを削除
4.2と3をリスト化できなくなるまで繰り返す
です。
現状組んでいるコードは下記になります。
Dim Cnt As Long Dim FSO As Object Dim FolderList()
Sub TEST()
Dim i as Long
Set FSO = CreateObject("Scripting.FileSystemObject")
Do
Call FolderSearch("C:\TEST(1)")
If UBound(FolderList) = -1 Then Exit Do
For i = 0 To UBound(FolderList)
FSO.DeleteFolder FolderList(i)
Next i
FolderList = Array()
Cnt = 0
Loop
Set FSO = Nothing
End Sub
Sub FolderSearch(myFolder)
Dim mySubFolder
With FSO.GetFolder(myFolder)
If .SubFolders.Count > 0 Then
For Each mySubFolder In .SubFolders
If FSO.GetFolder(mySubFolder).SubFolders.Count = 0 And FSO.GetFolder(mySubFolder).Files.Count = 0 Then
ReDim Preserve FolderList(Cnt)
FolderList(Cnt) = mySubFolder
Cnt = Cnt + 1
End If
Call FolderSearch(mySubFolder)
Next
End If
End With
End Sub
< 使用 Excel:Excel2010、使用 OS:Windows7 >
FSOが遅いのは割と有名な話です。
Dir関数 または Dirコマンド
なとで検索しながら他の方の回答をお待ちください。
サブフォルダを探すのは検索して出来ると思うけど、
空かどうかの判定がちょっとあやふや^^;
ちらっと検索限りではズバリのサンプルは無さそうなので、
自分でロジックを考えないといけないけど、
ちょっと思いつかないので、この程度の情報ですみません。
(まっつわん) 2018/04/19(木) 13:19
空フォルダとは?
1.目に見えるファイルやサブフォルダが無い
2.隠しファイルや隠しフォルダも含まれてない
3.目に見えるファイルや隠しファイルが含まれていない(サブフォルダは含まれていても
その中に目に見えるファイルや隠しファイルが含まれていない)
4.その他
3.の場合でしたら、FileSystemObjectでフォルダのSizeを取得し0であれば空
フォルダと判定できます。その時点で、そのフォルダ以下は調べなくてもOK、となります。
(カリーニン) 2018/04/19(木) 13:27
カリーニン様
返信ありがとうございます。
空フォルダの定義についてですが、3となります。
なるほど。上位階層のフォルダサイズが0だと確かに削除対象ですね。
しかしながら、ファイル数が多かったり、階層が深かったりすれば時間が
かかってしまいます。
ただ単にフォルダサイズが0か否かというような判定ってできるんでしょうか。
(すけろく) 2018/04/19(木) 14:13
まず、フォルダ一覧は、私がここで良く書いている DIR /B/S を利用したものを探し、パラメータを /B/S/A:D として、親フォルダ下の*.*を指定してみてください。 全部シートに吐くと量が多い場合、少し下の階層を指定して試すと良いでしょう。
後は、FSOでも使って、ファイル数フォルダ数サイズ等の情報を得て判定し、削除していけば良いでしょう。 ファイル含めてフォルダを消す、コマンドプロンプトの RMDIR /S/Q という手もあります。
問題は、サムネイルやExcelの排他情報等のシステムファイル属性を消せるかですね。普通に消そうとしても、システムファイル関係だからということで、OSに拒否されてしまうはずです。
(???) 2018/04/19(木) 16:53
敢えて自作をあきらめる手もありますよ^^;
(まっつわん) 2018/04/19(木) 16:59
???様
いろいろ検索もしながら下記コードを作成し、フォルダ一覧も取得できました。
あとは取得できた順で判定しながら削除となります。
例えば「C:\TEST(1)\TEST1\Test2」というようなフォルダ構成があり、
基本となるフォルダ(TEST(1))以下がすべて空フォルダの場合には
C:\TEST(1)のみが残るようにするため、
C:\TEST(1)\TEST1\Test2
C:\TEST(1)\TEST1
の順で削除しなければいけないと思うのですが(これはsizeを取得したときに
データが多いフォルダだと時間がかかるため)、階層の深さ順に並べ替える
必要がありますよね?
Sub TEST2()
Dim Fl
Fl = FolderSearch("C:\TEST(1)", "*.*")
For i = 0 To UBound(Fl)
Debug.Print Fl(i)
Next i
End Sub
Function FolderSearch(SEARCH_DIR, SEARCH_FILE)
Dim TMPFile As String
Dim strCmd As String
Dim buf() As Byte
Dim FileNum As Long
Dim TargetPath
TMPFile = Environ("TEMP") & "\Dir.tmp"
strCmd = "Dir """ & SEARCH_DIR & "\" & SEARCH_FILE & """ /b/s/a:d > """ & TMPFile & """"
With CreateObject("Wscript.Shell")
.Run "cmd /c" & strCmd, 7, True
End With
If Len(Dir(TMPFile)) Then
If FileLen(TMPFile) < 1 Then
Kill TMPFile
TargetPath = Array("")
Exit Function
End If
Else
TargetPath = Array("")
Exit Function
End If
FileNum = FreeFile
Open TMPFile For Binary As #FileNum
ReDim buf(1 To LOF(FileNum))
Get #FileNum, , buf
Close #FileNum
Kill TMPFile
FolderSearch = Split(StrConv(buf, vbUnicode), vbCrLf)
End Function
まっつわん様
自社のルールでフリーソフトはNGでした。
手間を考えると有償のソフトウェアの購入を上長に懇願しましたが
結果NGでした。(^^;)
(すけろく) 2018/04/20(金) 09:43
Sub test()
Const cPATH = "C:\TEST(1)\"
Dim AR As Object
Dim cFiles() As String
Dim i As Long
Set AR = CreateObject("System.Collections.ArrayList")
cFiles = Split(CreateObject("WScript.Shell").Exec("CMD /C DIR /A:D/B/S """ & cPATH & "*.*""").StdOut().ReadAll(), vbNewLine)
For i = 0 To UBound(cFiles) - 1
AR.Add cFiles(i)
Next i
AR.Sort
AR.Reverse
For i = 0 To AR.Count - 1
Cells(i + 1, "A").Value = AR(i)
Next i
End Sub
問題は、これに該当するフォルダ数が幾つあるかですねぇ。 数の問題でコントロールが対応できずエラー停止してしまうようならば、何回かに分けて、サブフォルダを親に指定するしかないでしょう。
(???) 2018/04/20(金) 17:46
それと、単純な逆順で済ませており、階層の深い順ではないですが、同じ親なら同じ文字列な訳ですし、これで十分ではないかと思います。
(???) 2018/04/20(金) 18:01
なんとなく書いてみた とりあえずは動いた
Const tFolder = "D:\"
CMDLine = "CMD /C DIR /A /S " & tFolder & " | FIND /V ""/"""
Set emptyDirList = CreateObject("Scripting.Dictionary")
Set DirData = CreateObject("WScript.Shell").Exec(CMDLine).StdOut
Do Until DirData.AtEndOfStream
getLine = DirData.ReadLine
If InStr(getLine, " のディレクトリ") Then
getPath = Mid(getLine, 2, InStrRev(getLine, " ") - 2)
DirData.ReadLine
emptyDirList.Add getPath, CLng(Left(DirData.ReadLine, 16))
End If
Loop
If Right(tFolder, 2) = ":\" Then emptyDirList.Remove tFolder
pathList = emptyDirList.Keys
For n = UBound(pathList) To LBound(pathList) Step -1
fPath = pathList(n)
If emptyDirList.Exists(fPath) Then
If emptyDirList.Item(fPath) Then
Do While emptyDirList.Exists(fPath)
emptyDirList.Remove fPath
fPath = Left(fPath, InStrRev(fPath, "\") - 1)
Loop
End If
End If
Next
Debug.Print Join(emptyDirList.Keys, vbCrLf)
問題点としてはFAT32だとemptyDirList.Keysのソートが必要になるかも? (2u) 2018/04/20(金) 20:11
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.