Dir 関数でパソコン内のファイルを検索する。

執筆者:

カテゴリ:

目的

  • パソコン内に指定ファイルが存在しているかどうかを調べる。

下記のような場合は「再帰処理」を使用した方が良いかもしれません。

  • 検索対象のフォルダが多数。
  • サブフォルダ(フォルダの中のフォルダ)まで検索したい。
  • ツリーのトップのフォルダ(ルートフォルダ)を指定して、ツリー全体を検索対象にしたい。

「vba 再帰処理 ファイル」「vba 再帰処理 fso」などのキーワードで検索すると目的の情報を得られると思います。

その一例

  1. パソコンのデスクトップの「folder1」フォルダに、いくつかのファイルが入っている状態でテストしてみます。
「C:¥Users¥xxx¥デスクトップ¥folder1」。xxx の部分は伏せ字になっています。ユーザーによって異なります。
「C:¥Users¥xxx¥デスクトップ¥folder1」。xxx の部分は伏せ字になっています。ユーザーによって異なります。
「folder1」にいくつかのファイルが入っています。
「folder1」にいくつかのファイルが入っています。
  • 「folder1」に存在するファイルを検索してみます。
    Sub 存在するファイルを検索()
    Debug.Print """" & Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥file1.txt") & """"
    End Sub
    1. 「Dir(“C:¥Users¥xxx¥デスクトップ¥folder1¥file1.txt”)」
      Dir( 検索条件 ) の書式になっています。
    2. “”””
      文字の始まりと終わりが分かりやすいように、ダブルクォーテーション「”」で囲んでいます。
      「”」二つで「”」を出力出来ます。「””」を「”」で囲んで「””””」としています。
    3. 実行結果は以下のようになりました。
  • ファイル名を取得出来ました。
    ファイル名を取得出来ました。
  • 「folder1」に存在しないファイルを検索してみます。
    Sub 存在しないファイルを検索()
    Debug.Print """" & Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥file0.txt") & """"
    End Sub
    1. 「file0.txt」
      file0.txt は存在していません。ファイルが存在しない場合、長さ 0 の文字列が返ってくるようです。
    2. 実行結果は以下のようになりました。
  • 長さ 0 の文字列が返ってきました。
    長さ 0 の文字列が返ってきました。
  • ワイルドカードで同じ拡張子のファイルを検索してみます。私が Dir 関数の動作をよく分かっていないので、その理解のために、Dir 関数を何回か実行してみます。
    Sub Dir関数の動作理解のために同じ拡張子のファイルを検索()
    Debug.Print """" & Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥*.txt") & """" 'Dir 関数実行 1 回目
    Debug.Print """" & Dir & """" '2 回目
    Debug.Print """" & Dir & """" '3 回目
    Debug.Print """" & Dir & """" '4 回目
    Debug.Print """" & Dir & """" '5 回目 'エラー発生
    Debug.Print """" & Dir & """" '6 回目
    End Sub
    1. 「Dir 関数実行 1 回目」
      1 回目は検索条件を指定しています。
    2. 「*.txt」
      ワイルドカードのアスタリスク「*」はその位置に複数の文字があることを表現しています。クエスチョンマーク「?」で何かの 1 文字を表現出来ます。
    3. 「2 回目」
      同じ検索条件で再検索する場合は Dir のみで実行します。
    4. 「3 回目」
      3 回目まではファイル名が出力されます。
  • Dir 3 回目までの結果。
    Dir 3 回目までの結果。
  • 「4 回目」
    3 回目までで検索条件に一致する全てのファイルを取得したので、 4 回目は、長さ 0 の文字列が返ってきます。
  • 4 回目は長さ 0 の文字列。
    4 回目は長さ 0 の文字列。
  • 「5 回目」
    5 回目でエラーが発生してマクロが中断されました。
  • 実行時エラー'5' プロシージャの呼び出し、または引数が不正です。
    実行時エラー’5′ プロシージャの呼び出し、または引数が不正です。
  • ワイルドカード+ループ処理で同じ拡張子のファイルを検索してみます。
    Sub ループ処理で同じ拡張子のファイルを検索()
    Dim a
    a = Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥*.txt") '実行順 1
    Do While a <> "" '2,6,10,14
    Debug.Print """" & a & """" '3,7,11
    a = Dir '4,8,12
    Loop '5,9,13
    End Sub '15
    1. 「Do … Loop」
      私が苦手とする Do Loop ステートメントを使用していますが、 Dir 関数のヘルプに載っていた制御構造です。
    2. 「実行順 1 … 15」
      処理の順番です。実行順 12 で長さ 0 の文字列が返ってきます。そのまま 13 へ進みますが、 14 で「Do While a <> “”」の条件に一致しないので Do Loop を抜けます。
    3. 実行結果は以下のようになりました。
  • 長さ 0 の文字列は出力されていません。
    長さ 0 の文字列は出力されていません。
  • ワイルドカードを「*.*」にしてフォルダ内の全てのファイルを検索してみます。
    Sub ループ処理で全てのファイルを検索()
    Dim a
    a = Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥*.*")
    Do While a <> ""
    Debug.Print """" & a & """"
    a = Dir
    Loop
    End Sub
    1. 実行結果は以下のようになりました。
  • 9 個のファイル名が出力されました。
    9 個のファイル名が出力されました。

    フォルダを検索

    Dir 関数はフォルダも検索できるようです。

    1. 上記で出てきた「folder1」の中に、いくつかのフォルダを追加してテストしてみます。
    「C:¥Users¥xxx¥デスクトップ¥folder1」。xxx の部分は伏せ字になっています。ユーザーによって異なります。
    「C:¥Users¥xxx¥デスクトップ¥folder1」。xxx の部分は伏せ字になっています。ユーザーによって異なります。
    「folder2」「folder3」「folder4」を追加しました。
    「folder2」「folder3」「folder4」を追加しました。
  • Dir 関数の第二引数に「vbDirectory」を指定してみます。
    Sub 第二引数にvbDirectoryを指定_フォルダを検索()
    Dim a
    a = Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥folder2", vbDirectory)
    Debug.Print """" & a & """"
    End Sub
    1. 「vbDirectory」
      vbDirectory は VBA.VbFileAttribute に入っている定数のようです。値は「16」と定義されているようです。
    2. 実行結果は以下のようになりました。
  • フォルダ名を取得出来ました。
    フォルダ名を取得出来ました。
  • 第二引数指定なしの場合、長さ 0 の文字列が返ってきました。
  • 長さ 0 の文字列。
    長さ 0 の文字列。
  • ループ処理でフォルダを検索してみます。
    Sub ループ処理_フォルダを検索()
    Dim a
    a = Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥*", vbDirectory)
    Do While a <> ""
    Debug.Print """" & a & """"
    a = Dir
    Loop
    End Sub
    1. 実行結果は以下のようになりました。フォルダ名のみ取得されると思っていましたが、ファイル名、ピリオドの記号も取得されています。
  • ピリオド、ファイル名、フォルダ名が取得されている。
    ピリオド、ファイル名、フォルダ名が取得されている。
  • 上記結果のピリオド「.」は現在のフォルダ(カレントフォルダというらしいです)を示す表記のようです。ピリオド 2 つの「..」は親フォルダという意味のようです。
  • 「folder1¥*」
    「folder1¥」でも同じ結果になりました。
  • フォルダ名のみ抽出する方法は、下記 Dir 関数のヘルプページに載っていました。
    下記ページの使用例のコメント部分は英語になっていますが、 VBE で Dir 関数のヘルプを見ると日本語のコメントが付いていました。
  • 私の場合、上記ヘルプページに載っている以外の方法を知らないので、ヘルプそのままのようになってしまいますが、良ければご覧ください。
    Sub ループ処理_フォルダ名のみ抽出()
    Dim a
    a = Dir("C:¥Users¥xxx¥デスクトップ¥folder1¥", vbDirectory)
    Do While a <> ""
    If a <> "." And a <> ".." Then
    If (GetAttr("C:¥Users¥xxx¥デスクトップ¥folder1¥" & a) And vbDirectory) = vbDirectory Then
    Debug.Print """" & a & """"
    End If
    End If
    a = Dir
    Loop
    End Sub
    1. 「If a <> “.” And a <> “..” Then」
      現在のフォルダ「.」と親フォルダ「..」以外の場合。
    2. 「GetAttr() And vbDirectory) = vbDirectory」
      フォルダの属性を取得して、定数 vbDirectory(=16)と一致しているか判定。
    3. 実行結果は以下のようになりました。
  • フォルダ名のみになっている。
    フォルダ名のみになっている。
  • GetAttr 関数のテストも行ってみました。まずはファイルの属性を取得してみます。
    Sub GetAttr関数でファイルの属性取得()
    Debug.Print GetAttr("C:¥Users¥xxx¥デスクトップ¥folder1¥file1.txt")
    End Sub
    1. 「GetAttr」
      GetAttr 関数は「属性の値」の合計値を返すようです。「属性の値」は、フォルダ属性「16」、アーカイブ属性「32」のように定数で決まっているようです。
      GetAttr 関数 (Visual Basic for Applications) | Microsoft Learn
      https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/getattr-function
    2. 実行結果は以下のようになりました。
  • 32 は「アーカイブ」属性を持っているという意味のようです。
    32 は「アーカイブ」属性を持っているという意味のようです。
  • 次はフォルダの属性を取得してみます。
    Sub GetAttr関数でフォルダの属性取得()
    Debug.Print GetAttr("C:¥Users¥xxx¥デスクトップ¥folder1¥folder2")
    End Sub
    1. 結果は以下のようになりました。
  • 48。おそらく 16+32 だと思います。フォルダ属性+アーカイブ属性を持っているようです。
    48。おそらく 16+32 だと思います。フォルダ属性+アーカイブ属性を持っているようです。
  • And 演算子でビット単位の比較というものを行うと「16」が取得できるようです。私の場合、ビット単位の比較というのが分かっていません。
    Sub And_vbDirectoryを付加_GetAttr関数でフォルダの属性取得()
    Debug.Print GetAttr("C:¥Users¥xxx¥デスクトップ¥folder1¥folder2") And vbDirectory
    End Sub
    1. 実行結果は以下のようになりました。
  • 16 を取得できました。定数 vbDirectory の値と一致しています。
    16 を取得できました。定数 vbDirectory の値と一致しています。
  • 「And vbDirectory」の部分を「And vbArchive」に変更すると以下の結果になりました。
  • 32。アーカイブ属性も持っているようです。
    32。アーカイブ属性も持っているようです。

    テスト結果ストック

    デスクトップに作成した「folder10」
    デスクトップに作成した「folder10」
    folder10 の中にあるファイル、フォルダ。読み取り専用(ReadOnly)、隠しファイル(Hidden)、標準(Normal)、フォルダ(Directory)
    folder10 の中にあるファイル、フォルダ。読み取り専用(ReadOnly)、隠しファイル(Hidden)、標準(Normal)、フォルダ(Directory)

    実行したマクロ

    Private Sub 呼出し関数(path)
    'vbNormal 0 標準
    'vbReadOnly 1 読み取り専用
    'vbHidden 2 隠しファイル
    'vbSystem 4 システムファイル。Mac 使用不可
    'vbDirectory 16 フォルダ
    'vbArchive 32 前回バックアップ以降変更有。Mac 使用不可
    'vbAlias 64 Mac のみ
    Debug.Print "path="; path
    Debug.Print "GetAttr="; GetAttr(path)
    Debug.Print "vbNormal="; GetAttr(path) And vbNormal
    Debug.Print "vbReadOnly="; GetAttr(path) And vbReadOnly
    Debug.Print "vbHidden="; GetAttr(path) And vbHidden
    Debug.Print "vbSystem="; GetAttr(path) And vbSystem
    Debug.Print "vbDirectory="; GetAttr(path) And vbDirectory
    Debug.Print "vbArchive="; GetAttr(path) And vbArchive
    Debug.Print "vbAlias="; GetAttr(path) And vbAlias
    End Sub
    Sub GetAttr関数で属性を調べる()
    Const a = "C:¥Users¥xxx¥デスクトップ¥folder10"
    呼出し関数 (a & "¥ReadOnly-Hidden.txt")
    呼出し関数 (a & "¥ReadOnly.txt")
    呼出し関数 (a & "¥Normal.txt")
    呼出し関数 (a & "¥Hidden.txt")
    呼出し関数 (a & "¥Directory")
    End Sub

    実行結果を表にまとめたもの

    path

    GetAttr
    合計値

    vb
    Normal
    定数=0
    vb
    ReadOnly
    定数=1
    vb
    Hidden
    定数=2
    vb
    System
    定数=4
    vb
    Directory
    定数=16
    vb
    Archive
    定数=32
    vb
    Alias
    定数=64
    ReadOnly-Hidden.txt3501200320
    ReadOnly.txt3301000320
    Normal.txt3200000320
    Hidden.txt3400200320
    Directory1600001600

    「Directory」の GetAttr の結果が 16 になっています。上記ではフォルダの GetAttr の結果は 48 と出てきました。 48 を再現しようとしてみましたが、なぜか出来ないままです。

    テスト環境

    • Windows 10(64 ビット)
    • Microsoft Office Excel 2003

    以上、閲覧ありがとうございました。