| 
    
     |  | ▼neptune さん、ありがとうございます。 > ▼kanabun さん:
 > ちょっとだけお邪魔します。
 >
 > 宣言部分だけ何とかなりそうなので一応書いておきます。
 
 > ヘッダーファイルから拾いました。
 >
 > Public Enum FINDEX_INFO_LEVELS
 >   FindExInfoStandard
 >   FindExInfoMaxInfoLevel
 > End Enum
 > Public Enum FINDEX_SEARCH_OPS
 >   FindExSearchNameMatch
 >   FindExSearchLimitToDirectories
 >   FindExSearchLimitToDevices
 >   FindExSearchMaxSearchOp
 > End Enum
 >
 > '多分lpSearchFilterは0で良いと思います。
 
 > Public Enum FINDEX_SEARCH_OPS
 の
 >   FindExSearchLimitToDirectories
 が、文字通りに解釈すると、「Directoryだけに制限する」と
 読めるので、早速、これを取り入れてみました。
 
 '-------------------------------------
 Option Explicit
 
 Private Const MAX_PATH = 260
 Private Const INVALID_HANDLE_VALUE = (-1)
 
 ' WIN32_FIND_DATA構造体
 Private Type WIN32_FIND_DATA
 dwFileAttributes  As Long
 ftCreationTime   As Currency
 ftLastAccessTime  As Currency
 ftLastWriteTime   As Currency
 nFileSizeHigh    As Long
 nFileSizeLow    As Long
 dwReserved0     As Long
 dwReserved1     As Long
 cFileName(1 To MAX_PATH * 2) As Byte 'Unicode
 cAlternate(1 To 14 * 2) As Byte    'Unicode
 End Type
 
 Private Declare Function FindFirstFile _
 Lib "kernel32" Alias "FindFirstFileW" _
 (ByVal lpFileName As Long, _
 lpFindFileData As WIN32_FIND_DATA) As Long
 
 Public Enum FINDEX_INFO_LEVELS
 FindExInfoStandard
 FindExInfoMaxInfoLevel
 End Enum
 Public Enum FINDEX_SEARCH_OPS
 FindExSearchNameMatch
 FindExSearchLimitToDirectories
 FindExSearchLimitToDevices
 FindExSearchMaxSearchOp
 End Enum
 
 Declare Function FindFirstFileEx& _
 Lib "kernel32" Alias "FindFirstFileExW" _
 (ByVal lpFileName&, _
 ByVal InfoLevelIdReserved&, _
 lpFindFileData As WIN32_FIND_DATA, _
 ByVal SearchOp&, _
 ByVal lpSearchFilterReserved&, _
 ByVal dwAdditionalFlagsReserved&)
 
 ' LPCTSTR lpFileName,       // 検索するファイル名
 ' FINDEX_INFO_LEVELS fInfoLevelId, // データの情報レベル
 ' LPVOID lpFindFileData,      // 返された情報へのポインタ
 ' FINDEX_SEARCH_OPS fSearchOp,   // 実行するフィルタ処理のタイプ
 ' LPVOID lpSearchFilter,      // 検索条件へのポインタ
 ' DWORD dwAdditionalFlags     // 補足的な検索制御フラグ
 
 Private Declare Function FindNextFile _
 Lib "kernel32" Alias "FindNextFileW" _
 (ByVal hFindFile As Long, _
 lpFindFileData As WIN32_FIND_DATA) As Long
 Private Declare Function FindClose _
 Lib "kernel32" _
 (ByVal hFindFile As Long) As Long
 '-------------------------------------------------------------
 
 Sub Try_FindFileEx()
 Dim myPath As String
 Dim strFind As String
 Dim f As String
 Dim n&
 Dim myList() As String
 Dim t!
 
 t = Timer()
 myPath = "D:\(Data)"
 strFind = "abc.*"
 FindFileEx myPath, strFind, myList(), n '★呼び出し
 
 Debug.Print "'★Try_FindFileEx"; Timer() - t
 If n Then
 MsgBox Join(myList, vbCr), _
 , strFind & " ---> " & n & " Files"
 Else
 MsgBox "該当ファイルなし"
 End If
 End Sub
 
 Private Sub FindFileEx(Pathname$, strFind$, myList$(), _
 fCount&, Optional SearchChild As Boolean = True)
 Dim p As String
 Dim fDATA As WIN32_FIND_DATA
 Dim lngAttribute As Long
 Dim f As String
 Dim hFile As Long
 Dim SubDirs() As String, nSub As Long, i As Long
 
 If Right$(Pathname, 1) <> "\" Then Pathname = Pathname & "\"
 
 '指定フォルダ内の指定ファイルの検索
 p = Pathname & strFind
 hFile = FindFirstFile(StrPtr(p), fDATA)
 If hFile <> INVALID_HANDLE_VALUE Then
 Do
 f = fDATA.cFileName
 f = Left$(f, InStr(f, vbNullChar) - 1)
 If (fDATA.dwFileAttributes And vbDirectory) = 0 Then
 fCount = fCount + 1
 ReDim Preserve myList(1 To fCount)
 myList(fCount) = Pathname & f
 End If
 Loop While FindNextFile(hFile, fDATA)
 FindClose hFile
 End If
 
 'つぎに 指定パス 内のサブフォルダの検索をおこなう
 If SearchChild Then
 p = Pathname & "*"
 hFile = FindFirstFileEx(StrPtr(p), _
 0&, _
 fDATA, _
 FindExSearchLimitToDirectories, _
 0&, _
 0&)
 If hFile = INVALID_HANDLE_VALUE Then Exit Sub
 Do
 f = fDATA.cFileName
 f = Left$(f, InStr(f, vbNullChar) - 1)
 If (fDATA.dwFileAttributes And vbDirectory) Then
 If Not f Like ".*" Then
 nSub = nSub + 1
 ReDim Preserve SubDirs(1 To nSub)
 SubDirs(nSub) = Pathname & f
 End If
 End If
 Loop While FindNextFile(hFile, fDATA)
 FindClose hFile
 
 If nSub Then
 For i = 1 To nSub
 'サブフォルダ内の指定ファイルの検索
 FindFileEx SubDirs(i), strFind, myList(), fCount
 Next
 End If
 End If
 
 End Sub
 
 '----------------------
 しかし、FindExSearchLimitToDirectories を指定しているにも
 かかわらず、残念ながら、これでもファイルが検索されてしまい
 ました。。。
 > ですが、MSDNをさまよってみましたが、findfirstfileexが一番
 > 可能性ありそうな気はします?
 いいところまで来たのか、無駄な努力をしているのか?
 その辺が知りたいです。。
 
 あと、マクロマンさんご紹介の「目安箱」のなかに、
 ちゃっぴさんのサブフォルダを含むファイルの一覧の
 各種サンプルがありますが、FindFile系API以外では、
 >  【その2 コマンドプロンプトDIRコマンド Version】
 >'【要参照】「Windows Scripting Host Object Model」
 >
 が、有効なことを再認識しました。(^^
 <引用>
 >ファイルの入出力を介しますが、FSOよりも動作が速いのが魅力です。
 >また、サブフォルダの検索のOn/Offをオプション"/S"だけで
 >切り替えられるのも魅力です。
 >
 >ただ、残念なことにOSに依存します。 </引用>
 
 (↓kanabun が変数名など勝手に変えちゃってます)
 Sub RunDir()
 Dim oWShell   As WshShell
 Dim objRedirectFile As File
 Dim objRedirectTXT As TextStream
 Dim strPathFilename  As String    '対象フォルダパス
 Dim strRedirectPath As String     '一時ファイルパス
 Dim ko    As Long
 Dim varFileList   As Variant
 Dim t!
 
 t = Timer
 Set oWShell = New WshShell
 
 strPathFilename = "D:\(Data)\abc.*"
 strRedirectPath = "D:\(Data)\Temp\DirTemp.txt"
 
 ko = oWShell.Run("CMD /C DIR """ & strPathFilename _
 & """ /A-D /B /S > """ & strRedirectPath & """", 7, True)
 Set oWShell = Nothing
 
 If ko = 0 Then
 Dim io As Integer
 Dim ss As String
 
 io = FreeFile()
 Open strRedirectPath For Binary As io
 ReDim buf(1 To LOF(io)) As Byte
 Get #io, , buf
 Close io
 ss = StrConv(buf, vbUnicode)
 End If
 t = Timer - t
 MsgBox ss,,t
 End Sub
 
 あるフォルダ内の "abc*.xls" というファイルを
 サブフォルダも含めて
 通常のDirの再帰で検索すると、 7.2秒、
 Sub RunDir() で検索すると、  2.4〜2.7秒、
 このスレッドで最初に提示して(削除してしまった)
 ★Try_FindFileO で検索すると、 1.72秒
 といった感じです。
 ★Try_FindFileO は、よく見るアルゴリズム
 ( FindFirstFile で フォルダ内のすべてのファイルを検索し、
 その中から、指定したパターンと一致するファイルを取り出し、
 同時に、属性がDirectoryであれば 自身を再帰呼び出しする )
 なので、Dirの再帰と同じアルゴリズムなのです。
 Dir関数 も FindFirstFile関数も ワイルドカードを使った
 特定のファイルの検索ができるのに、サブフォルダの検索も
 やろうとなると、とたんに FileSystemObject同様、すべての
 ファイルを取得しなければならない。そこが効率悪いと思うのに
 (1) 指定ファイル("abc*.xls")の検索
 (2) サブフォルダの検索
 をしているサンプルが、いまのところ、どこにもないということは
 FindFirstFileExでも、(2)ができないんでしょうかね?
 
 (1)はFindFirstFileで、
 (2)の部分だけ Fso.GetFolder(Pathname).SubFolders
 で実験してみた結果は、 7.0 秒でした。
 
 |  |