VB6で指定フォルダ以下にあるファイル名を列挙するには?

解決


たくろう  2009-12-09 16:13:45  No: 102120  IP: [192.*.*.*]

お世話になります。

VB6で指定フォルダ以下(サブフォルダ、複数階層も)にある
ファイル名を取得したいと思っています。

検索してみたところ、いろいろなやり方や抽出条件指定がありました。
単純に、簡単に、フルパスのファイル名を列挙する方法を教えてください。

以上、よろしくお願いいたします。

編集 削除
魔界の仮面弁士  2009-12-09 19:47:26  No: 102121  IP: [192.*.*.*]

Dir 関数の場合、入れ子で呼び出す機能が無いので、階層を辿る場合には
少々工夫が必要になりますね(と言いつつ、私も Dir を使う事が多いですが)。


> 単純に、簡単に、
階層を再帰的に走査する場合には、FileSystemObject を使う事も
検討してみてください。高機能な分、Dir よりも若干低速ですが、その分、
取り扱いは Dir よりも簡単になるかと思います。単純かは別として。


> フルパスのファイル名を列挙する方法を教えてください。
別案として、DIR コマンドで列挙するとか。

Option Explicit

Private Sub Form_Load()
    Text1.Text = "C:\Program Files\Microsoft Visual Studio\VB98"
    Command1.Caption = "列挙"
End Sub

Private Sub Command1_Click()
    Dim files() As String
    files = GetFiles(Text1.Text)
    
    '確認用
    Dim v As Variant
    For Each v In files
        Debug.Print v
    Next
End Sub

Public Function GetFiles(ByVal directory As String) As String()
    Dim wk As String
    wk = Environ("TMP") & "\" & Format(Now, "yyyyMMddhhmmss")

    CreateObject("WScript.Shell").Run """" & Environ("COMSPEC") _
        & """ /C DIR """ & directory & """ /S /B > """ & wk & """", _
        vbNormalFocus, True
    With CreateObject("Scripting.FileSystemObject").OpenTextFile(wk)
        Dim s As String
        If Not .AtEndOfLine Then s = .ReadAll()
        GetFiles = Split(Left(s, Len(s & ":*") - 2), vbNewLine)
        .Close
    End With
    Kill wk
End Function

編集 削除
たくろう  2009-12-09 23:00:24  No: 102122  IP: [192.*.*.*]

オショウさん、魔界の仮面弁士さん、ありがとうございます。

> Dir 関数の場合、入れ子で呼び出す機能が無いので、階層を辿る場合には
> 少々工夫が必要になりますね(と言いつつ、私も Dir を使う事が多いですが)。

これが良く理解できなかったので、もっとスマートな方法がないかと思いました。
ご提示いただいたコードはスマートで機能実現できました。

FileSystemObjectについて調べて中身を理解してみたいと思います。

編集 削除
魔界の仮面弁士  2009-12-10 12:49:23  No: 102123  IP: [192.*.*.*]

> FileSystemObjectについて調べて中身を理解してみたいと思います。

FileSystemObject 版のサンプルを提示しておきます。


Option Explicit

Private Sub Form_Load()
    Text1.Text = "C:\Program Files\Microsoft Visual Studio\VB98"
    Command1.Caption = "列挙"
End Sub

Private Sub Command1_Click()
    Dim Files() As Variant
    Files = GetFiles(Text1.Text, True)

    '確認用
    Dim v As Variant
    For Each v In Files
        Debug.Print v
    Next
End Sub

Public Function GetFiles(ByVal directory As String, Optional includeDirName As Boolean = False) As Variant()
    Dim Files As Object, FSO As Object
    Set Files = CreateObject("Scripting.Dictionary")
    Set FSO = CreateObject("Scripting.FileSystemObject")

    With FSO.GetFolder(directory)
        If includeDirName Then
            'ディレクトリ名も出力
            Files.Add Files.Count, .Path & IIf(.IsRootFolder, "", "\")
        End If

        Dim subItem As Object, fileName As Variant

        'サブディレクトリを再帰
        For Each subItem In .SubFolders
            For Each fileName In GetFiles(subItem.Path, includeDirName)
                Files.Add Files.Count, fileName
            Next
        Next

        '直下のファイル群を列挙
        For Each subItem In .Files
            Files.Add Files.Count, subItem.Path
        Next
    End With
    GetFiles = Files.Items()
End Function

編集 削除
魔界の仮面弁士  2009-12-10 18:19:43  No: 102124  IP: [192.*.*.*]

>> Dir 関数の場合、入れ子で呼び出す機能が無いので、階層を辿る場合には
>> 少々工夫が必要になりますね(と言いつつ、私も Dir を使う事が多いですが)。
> これが良く理解できなかったので、もっとスマートな方法がないかと思いました。

Dir/Dir$ 関数バージョンです。

列挙中に、別のディレクトリを走査する事は出来ませんので、
列挙後に、別のディレクトリを走査するようにしています。

-----
Option Explicit

Private Sub Form_Load()
    Text1.Text = "C:\Program Files\Microsoft Visual Studio\VB98"
    Command1.Caption = "列挙"
End Sub

Private Sub Command1_Click()
    Dim Files() As String
    Files = GetFiles(Text1.Text, True)

    '確認用
    Dim v As Variant
    For Each v In Files
        Debug.Print v
    Next
End Sub

Public Function GetFiles(ByVal directory As String, Optional includeDirName As Boolean = False) As String()
    directory = directory & IIf(directory Like "*\", "", "\")

    '下位要素を列挙する
    Dim directories As Collection, Files As Collection
    Set directories = New Collection
    Set Files = New Collection
    Dim dirName As String
    dirName = Dir$(directory, vbDirectory Or vbSystem Or vbHidden Or vbReadOnly)
    Do Until dirName = ""
        If dirName <> "." And dirName <> ".." Then
            If (GetAttr(directory & dirName) And vbDirectory) = vbDirectory Then
                directories.Add directory & dirName
            Else
                Files.Add directory & dirName
            End If
        End If
        dirName = Dir$()
    Loop

    Dim result As Object
    Set result = CreateObject("Scripting.Dictionary")

    If includeDirName Then
        'ディレクトリ名も出力
        result.Add result.Count, directory & IIf(directory Like "*\", "", "\")
    End If

    'このディレクトリのファイルを出力
    Dim filePath As Variant
    For Each filePath In Files
        result.Add result.Count, filePath
    Next

    '列挙した下位ディレクトリに対して再帰
    Dim dirPath As Variant
    For Each dirPath In directories
        For Each filePath In GetFiles(dirPath, includeDirName)
            result.Add result.Count, filePath
        Next
    Next

    'Variant 配列から String配列に変換
    GetFiles = Split(Join(result.Items(), vbNullChar), vbNullChar)
End Function

編集 削除
たくろう  2009-12-14 22:13:40  No: 102125  IP: [192.*.*.*]

魔界の仮面弁士さん、非常にわかりやすい
サンプルコードをありがとうございました。
また、何かあればよろしくお願いいたします。

本件、解決とさせていただきます。

編集 削除