【VBA】Dir関数を使ってフォルダ内の最新のファイルを取得する

VBA

※この記事にはプロモーションが含まれています。

定期的にクラウドからCSVファイルをダウンロードするのですが、毎回手動で最新のファイルを確認してデータを取るのが面倒ですね…

VBAのDir関数を使うと条件に合うファイルを探すことができますよ。

レンタルサーバー 高速・高機能・高安定性の【エックスサーバー】
高速かつ高い安定性を誇る高性能レンタルサーバー【エックスサーバー】稼働率99.99%以上の高い安定性で、業界トップクラスの高コストパフォーマンスを誇る高品質レンタルサーバーです。月額990円(税込)から利用可能。まずは無料お試し10日間。

Dir関数とは

 Dir関数は、VBA(Visual Basic for Applications)でファイルやフォルダの検索に使用される非常に便利な関数です。この関数は、指定したパスに存在するファイルやフォルダの名前を取得するのに使われます。

 ただ、Dir関数は独特の動作のある関数ですので、少し前置きが長くなりますがその挙動や注意点をよく把握してDir関数を使いこなしましょう。

基本動作

 Dir関数は検索結果を変数に一時的に格納して使うのが一般的です。変数に格納しなくても使用できますが、変数に格納しておくことで後続の処理に便利です。Dir関数は初回呼び出しで検索パターンに一致するファイルやフォルダの名前を返し、その後の呼び出しでは次に一致するファイルやフォルダを返すという仕組みです。

 また、検索するファイルのパターンについては後述しますので今はわからなくても大丈夫です。

'変数なし
MsgBox Dir("C:\MyFolder\*.*")
MsgBox Dir
'変数あり
Dim folderPath As String
Dim fileName As String
    
    ' フォルダのパスを指定
    folderPath = "C:\MyFolder\*.*"
    
    ' 最初のファイルを取得して表示
    fileName = Dir(folderPath)
    MsgBox fileName
    
    ' 次のファイルを取得して表示
    fileName = Dir
    MsgBox fileName

初回の呼び出し

 最初に呼び出すときには、パスとファイル名のパターン(例: *.txt)を指定します。これにより、最初に見つかったファイルやフォルダの名前が返されます。

注意点

 Dir関数は、最初に引数なしで Dir( ) を呼び出すとエラーが発生します。初回の呼び出し時に必ず検索パスやファイル名のパターンを指定する必要があります。

次のファイルの取得

 Dir関数を再度引数なしで呼び出すことで、次のファイルやフォルダの名前を取得します。このプロセスを繰り返し、ディレクトリ内のすべての項目を取得できます。

注意点

 Dir関数は毎回パスとパターンを指定して呼び出すと、その都度ディレクトリの最初のファイル名が返されます。このため、同じファイル名が繰り返し取得されてしまい、他のファイルを取得できません。2回目以降は引数なしの Dir( ) を使って次のファイルを取得します。

 Dir関数は、一度呼び出すとその検索結果を内部で記憶します。このため、次に Dir を呼び出すまでその状態が保持され、次のファイルを取得できます。しかし、別のディレクトリやファイルを検索するために新しいパスやパターンを指定して Dir を呼び出すと、以前の検索結果がリセットされて内部の状態が初期化されてしまいます。これにより、元のディレクトリ内の検索を続行できなくなりますので注意が必要です。

検索結果がリセットされてしまった例

Dim fileName As String

    ' 最初のディレクトリでファイルを検索
    fileName = Dir("C:\MyFolder\*.*")
    Debug.Print "最初の検索: " & fileName
    
    ' 次のファイルを取得
    fileName = Dir
    Debug.Print "次のファイル: " & fileName
    
    ' 別のディレクトリを検索 (これで以前の検索結果がリセットされる)
    fileName = Dir("C:\AnotherFolder\*.*")
    Debug.Print "別のディレクトリ検索: " & fileName
    
    ' 元のディレクトリ情報はリセットされている
    fileName = Dir
    Debug.Print "リセット後の次のファイル: " & fileName

 複数のディレクトリを扱う場合は、まず一つのディレクトリ内の検索を完了させてから次のディレクトリの検索を行うようにしましょう。

ループの終了

 すべてのファイルやフォルダを取得し終えると、空の文字列(” “が返されます。

 注意点

 Dir( )をループで繰り返し呼び出していると、すべてのファイルやフォルダを取得し終えた後に空の文字列(” “)が返されます。この状態でさらに Dir( )を呼び出すとエラーが発生しますので空文字列が返されたらループを終了させる必要があります。

 また、存在しないパスや不正なファイルを検索するとエラーが発生するため、エラー処理を適切に行うことが推奨されます。

Dim folderPath As String
Dim fileName As String
    
    ' 検索するディレクトリのパス
    folderPath = "C:\MyFolder\*.*"
    
    ' 最初のファイルを取得
    fileName = Dir(folderPath)
    
    ' ファイルが存在する場合はループして表示
    If fileName <> "" Then
        Do While fileName <> ""
            Debug.Print fileName
            fileName = Dir ' 次のファイルを取得
        Loop
    Else
        Debug.Print "指定されたフォルダにはファイルがありません。"
    End If

ファイル属性の指定

 Dir関数ではファイル属性を指定してファイルやフォルダの検索することができます。これによって、検索結果を特定の条件で絞り込むことができます。

ファイル属性定数2進数ビット位置説 明
vbNormal00000なし標準のファイルまたはフォルダ(デフォルトの設定)
vbReadOnly100010編集が制限されている読み取り専用のファイル
vbHidden200101隠しファイルや隠しフォルダ
vbSystem401002OSや重要なプログラムによって使用されるシステムファイル
vbDirectory16100004フォルダ(ディレクトリ)を検索する際に使用

 ここで2進数、ビット位置などの難しい項目がありますが、こちらは下記のコード内でGetAttr( )関数で属性値を取り出し、ビット演算によってサブディレクトリがフォルダであることを確認しているために一応情報を載せています。

 ただ、この部分は完全に理解できなくても慣例的にコードを書いても問題ありません。なぜ、ビット演算を用いて確認しているかというと、例えば、隠しフォルダなど複数の属性を有する場合の検索に非常に高速で便利だからです。余裕があったらビット演算についても深堀りしてみて下さい。

指定したディレクトリ(フォルダ)内のサブディレクトリのリストを取得したい場合

Dim folderPath As String
Dim dirName As String
    
    ' 調べたいディレクトリのパスを指定
    folderPath = "C:\Users\John\Documents\"
    
    ' 最初のサブディレクトリを取得
    dirName = Dir(folderPath, vbDirectory)
    
    'ディレクトリ内のサブディレクトリを列挙
    Do While dirName <> ""
        ' "." と ".." を除外
        If dirName <> "." And dirName <> ".." Then
            ' サブディレクトリかどうかを確認
            If (GetAttr(folderPath & dirName) And vbDirectory) = vbDirectory Then
                Debug.Print "サブディレクトリ: " & dirName
            End If
        End If
        ' 次のディレクトリを取得
        dirName = Dir
    Loop

カレントディレクトリ(”.”)とその親ディレクトリ(”..”)の除外

 ファイル属性にvbDirectoryを指定すると作業ディレクトリであるカレントディレクトリ(”.”)とその上の階層の親ディレクトリ(”..”)までエントリーされます。普段コマンドライン操作やプログラミングに触れたことがある人には馴染みがありますが、VBAを使ってExcelやWordなどのアプリケーションのみを使っている方には概念が掴みづらいかもしれません。

 ただ、この部分も上記のビット演算の項同様、完全に理解できなくても慣例的にコードを書いても大丈夫です。

ワイルドカード

 ワイルドカードとは、特定の文字列を検索する際に、1つ以上の文字にマッチするために使う特殊な文字のことです。VBAでもLike演算子などを使用してワイルドカードを使った柔軟な文字列検索が可能です。

* (アスタリスク)

 任意の長さの文字列にマッチします。文字が0文字でも複数文字でもOKです。
 例: “a*e” は、”apple”, “axe”, “alphabet” にマッチしますが、”bat” にはマッチしません。

? (クエスチョンマーク)

 任意の1文字にマッチします。文字がちょうど1文字でなければなりません。
 : “b?g” は、”big”, “bag” にマッチしますが、”boggy” にはマッチしません。

# (ハッシュマーク)

任意の1桁の数字(0から9)にマッチします。
: “p#” は、”p1″, “p2″ にマッチしますが、”pa” にはマッチしません。

[] (角括弧)

角括弧内の任意の1文字にマッチします。指定した文字の範囲やセットに対応できます。
: “t[aeiou]p” は、”tap”, “tip”, “top” にマッチしますが、”tp” や “tpp” にはマッチしません。

[! ] (否定の角括弧)

[]内にない任意の1文字にマッチします。!を使うと指定した文字を除いたものにマッチします。
: “t[!aeiou]p” は、”tcp”, “tmp” などにマッチしますが、”tap” や “tip” にはマッチしません。

?クエスチョンマークとLike演算子の例

Dim myString As String
    myString = "cat"

    ' "cat" が "c?t" のパターンに一致するか確認
    If myString Like "c?t" Then
        MsgBox "一致しました!"
    Else
        MsgBox "一致しませんでした。"
    End If

正規表現について

 正規表現(Regular Expression)は、文字列の検索や置換、パターンマッチングに使われる強力なツールです。特定の文字列のパターンを記述することで、複雑な検索条件や置換処理を簡潔に行うことができます。例えば、数字のみを抽出したり、特定のフォーマットに従った文字列を探す際に非常に便利です。

VBAで正規表現を使う方法

 VBAは正規表現をネイティブにサポートしていませんが、参照設定を行って VBScript.RegExp オブジェクトを使うことで、正規表現を利用することができます。このオブジェクトを使用することで文字列のパターンマッチングや置換、検索が可能になります。

 ただ、ここではやや本題からそれていくので詳細な説明は割愛します。

次からはファイルやフォルダの作成日時、また更新日時について確認してみましょう。

👉 【最大10,000円割引!】 XServer レンタルサーバー招待リンク

ファイルの作成日時と更新日時

最新のファイルはどのように調べるのですか?

 まず、Windowsでのファイルに関連する重要なタイムスタンプには更新日時作成日時がありますが、それぞれのタイムスタンプがコピーやインターネットやクラウドからのダウンロードによってどのように変化するかを把握しないと、思った通りの結果が得られないことがありますのでこれらを整理して確認しておきましょう。

 また、作成日時更新日時は「ファイルを右クリック」 ➡ プロパティで確認することが出来ます。

作成日時

 作成日時は、ファイルやフォルダがシステム上に最初に作成された時刻を示すタイムスタンプです。ファイルが新しく作成された瞬間の日時を記録しており、ファイルが新たに作成されたときに設定されます。
 ただし、その後にファイルがコピーされたり、インターネットやクラウドからダウンロードされた場合は、作成日時がその時点の日時に更新されます。これは新しい場所や新しいシステムでファイルが「再作成」されたと見なされるためです。

更新日時

 更新日時は、そのファイルが最後に変更された時刻を示します。ファイルの内容が変更された場合にこのタイムスタンプが更新されます。たとえ小さな変更でもファイルが修正されたり保存された時にこの日時が記録されます。

 また、ダウンロードされたファイルの更新日時は、ダウンロードが完了した時点の日時に更新されますが、コピーされたファイルの更新日時は元のファイルの更新日時を保持しますので、ファイルの作成日時よりも更新日時が古くなる場合があるのはこのためです。

更新日時を取得するFileDateTime関数 

 FileDateTime関数は、VBAで特定のファイルの最終更新日時を取得するために使用される便利な関数です。この関数はファイルのタイムスタンプをシンプルに取得できるので FileSystemObject を使わずにファイルの日時を扱いたい場合に適しています。

 また、FileDateTime関数は指定したファイルの最終更新日時を Date 型として返します。

On Error GoTo ErrorHandler ' エラーハンドリングの開始
    
    Dim filePath As String
    Dim fileDate As Date
    
    ' ファイルのパスを指定
    filePath = "C:\Users\ExampleUser\Documents\NonExistentFile.xlsx"
    
    ' ファイルの最終更新日時を取得
    fileDate = FileDateTime(filePath)
    
    ' メッセージボックスで日時を表示
    MsgBox "ファイルの最終更新日時: " & fileDate
    Exit Sub
    
ErrorHandler:
    MsgBox "ファイルが見つかりません。パスを確認してください。"

 ファイルが存在しない場合はエラーが発生しますのでエラーハンドリングが必要です

特殊フォルダへのアクセス

 特殊フォルダとは、オペレーティングシステムが特定の用途のために予約・割り当てている特定のフォルダのことです。これらのフォルダはシステムの一部やユーザーデータを保存するために使われ、通常のフォルダとは異なる役割やアクセスパスが設定されています。

 下記は主な特殊フォルダの例です。

デスクトップフォルダ(Desktop)

ユーザーのデスクトップ画面に表示されるアイテム(ファイルやフォルダ)を保存するフォルダ。
C:\Users\ユーザー名\Desktop

ドキュメントフォルダ(My Documents)

ユーザーのドキュメントを保存するためのフォルダ。文書ファイルを保存する標準的な場所。
例:C:\Users\ユーザー名\Documents

ダウンロードフォルダ(Downloads)

ユーザーがブラウザや他のアプリケーションでダウンロードしたファイルを保存するフォルダ。
例:C:\Users\ユーザー名\Downloads

プログラムフォルダ(Program Files)

アプリケーションプログラムがインストールされる標準のフォルダ。32ビットアプリケーション用と64ビットアプリケーション用の2つのバージョンが存在。
例:C:\Program Files(64ビットアプリ用)、C:\Program Files (x86)(32ビットアプリ用)

環境変数を使って特殊フォルダにアクセスする

 環境変数は、コンピュータのシステム全体で共通の設定情報を保存するための変数です。これにより、プログラムやオペレーティングシステムが実行時に必要な情報(例: ユーザーのフォルダパスやシステム設定)に簡単にアクセスできるようになります。

環境変数を使用する必要性

 通常、自分のパソコンでのみフォルダにアクセスする場合は、ただ単純にユーザー名を入れたパスを指定するだけでわざわざ環境変数などを使う必要はありませんが、システムを汎用的に使用し、他の多くのパソコンからもアクセスする場合は、それぞれのパソコンのユーザー名が違うため、やはり環境変数を使用した構築が必要になります。

 この環境変数の値をVBAのEnviron関数によって取得することができます。

Dim downloadPath As String
    
    ' USERPROFILE環境変数を使ってダウンロードフォルダのパスを構成
    downloadPath = Environ("USERPROFILE") & "\Downloads\"
    
    Debug.Print downloadPath   ' イミディエイトウィンドウにパスを表示

ユーザーが「John」という名前でWindowsにログインしている場合の出力結果

C:\Users\John\Downloads\

 また他の環境変数を調べたい場合は、WindowsではPowerShellコマンドプロンプトなどのコマンドラインツールで下記のようにコマンドを使用することで環境変数の一覧を調べることができます。

コマンドプロンプト

set

PowerShell

Get-ChildItem Env:

短縮形のコマンドで入力した際のPowerShellでの出力例

PS C:\Users\John> gci env:
       :
TEMP                           C:\Users\John\AppData\Local\Temp
TMP                            C:\Users\John\AppData\Local\Temp
USERDOMAIN                     YOURDOMAIN
USERDOMAIN_ROAMINGPROFILE      YOURDOMAIN
USERNAME                       John
USERPROFILE                    C:\Users\John
windir                         C:\WINDOWS

次はいよいよ本題のコードです!

ダウンロードフォルダにある最新のCSVファイルを開く

 いままでの内容の復習なので問題ないと思いますが、ポイントは Dir関数 で条件に合うファイルを取り出し、ひとつひとつ更新日時を比較してより最新のファイルを変数に格納していくという流れです。

Sub OpenLatestCSVFile_Dir()

    Dim fileName As String
    Dim latestFile As String
    Dim latestDate As Date
    Dim fileDate As Date
    Dim downloadFolder As String
    Dim filePath As String

    ' 環境変数を使ってダウンロードフォルダのパスを取得
    downloadFolder = Environ("USERPROFILE") & "\Downloads\"

    ' 初期化
    latestDate = #1/1/1900# ' 適当に過去の日付
    latestFile = ""

    ' ダウンロードフォルダ内の最初のCSVファイルを取得
    fileName = Dir(downloadFolder & "*.csv")

    ' ファイルが存在する限りループ
    Do While fileName <> ""
        ' フルパスを取得してファイルの更新日時を取得
        filePath = downloadFolder & fileName
        fileDate = FileDateTime(filePath)

        ' 更新日時が最新かどうかを確認
        If fileDate > latestDate Then
            latestDate = fileDate
            latestFile = filePath
        End If

        ' 次のCSVファイルを取得
        fileName = Dir
    Loop

    ' 最新のCSVファイルが見つかった場合
    If latestFile <> "" Then
        ' CSVファイルを開く
        Workbooks.Open latestFile
        MsgBox "最新のCSVファイルを開きました: " & latestFile
    Else
        MsgBox "ダウンロードフォルダにCSVファイルが見つかりませんでした。"
    End If

End Sub

ファイルを開くことができました!

おわりに

 ここではファイルを開くだけでしたが、更新日時の新しいファイルや特定のパターンのファイルを探して必要なデータをだけを自動的に取得するようにしたり、さらに複数のファイルから同時に取得するようなコードが組めれば毎回手動で作業しなければならない手間は省けますよね。

 最後までご覧頂きありがとうございました。

 また、フォルダパス操作に関連して 本ブログで紹介しているFileSystemObject を使用すると特定のパターンのファイルのみを移動させたり、膨大な量のファイルを整理したりなどさらに発展した使い方ができるようになります。

タイトルとURLをコピーしました