【VBA】FSOで複数ファイルを更新日時順に一括連番リネームする方法

目次

はじめに

デジカメで撮影した大量の写真ファイルや、日々作成される業務レポート。「ファイル名がバラバラで整理しにくい」「時系列に並んだ連番にしたい」と感じたことはありませんか?

一つずつ手作業でリネームするのは大変ですが、VBAの FileSystemObject (FSO) を使えば、フォルダ内の複数ファイルを更新日時が古い順に、001.jpg, 002.jpg のように一括で連番リネームできます。

この記事では、安全かつ確実にファイル名を一括変更する、少し高度なVBAテクニックを分かりやすく解説します。


連番リネームの処理方針

単純にファイル名を変更していくだけでは、「AをBにリネームしたいが、Bが既に存在する」といった名前の衝突が起きてエラーになる可能性があります。

そこで、今回は以下の安全な手順で処理を行います。

  1. 情報収集: 対象フォルダから、指定した拡張子のファイル情報(ファイルオブジェクトと更新日時)を全て集めます。
  2. 並べ替え: 集めたファイル情報を、更新日時が古い順に並べ替えます(ソート)。
  3. 一時リネーム: 並べ替えた順に、全てのファイルを一度「絶対に重複しない一時的な名前」にリネームします。
  4. 最終リネーム: 一時的な名前にしたファイルを、001, 002 といった最終的な連番にリネームします。

この「一時リネーム」を挟むことで、名前の衝突を確実に防ぐことができます。


ファイルを一括連番リネームするVBAコード

ここでは、Excelファイルと同じ階層にある「撮影データ」フォルダ内の、拡張子が「.jpg」のファイルを、更新日時順に「Photo_001.jpg」のような名前に変更するコードを作成します。

完成コード

'ファイル情報(オブジェクトとソートキー)を格納するユーザー定義型
Private Type FileInfo
    FileObject As Object
    SortKey As Date
End Type

Sub RenameFilesWithSequentialNumber()

    '== 変数を定義します ==
    Dim objFSO As Object
    Dim targetFolder As Object
    Dim targetFile As Object
    Dim fileExtension As String
    
    Dim targetFiles() As FileInfo  '収集したファイル情報を格納する配列
    Dim tempInfo As FileInfo       '並べ替え時の一時保管用
    Dim fileCount As Long
    Dim i As Long, j As Long

    '== 基本設定 ==
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set targetFolder = objFSO.GetFolder(ThisWorkbook.Path & "¥撮影データ")
    fileExtension = "jpg" '対象の拡張子(ドットは不要)
    
    fileCount = 0

    '== 1. 対象フォルダからファイル情報を収集します ==
    For Each targetFile In targetFolder.Files
        If LCase(objFSO.GetExtensionName(targetFile.Path)) = fileExtension Then
            fileCount = fileCount + 1
            ReDim Preserve targetFiles(1 To fileCount)
            Set targetFiles(fileCount).FileObject = targetFile
            targetFiles(fileCount).SortKey = targetFile.DateLastModified
        End If
    Next targetFile
    
    If fileCount = 0 Then
        MsgBox "対象のファイルが見つかりませんでした。", vbInformation
        Exit Sub
    End If

    '== 2. 収集したファイル情報を更新日時順に並べ替えます(バブルソート) ==
    For i = 1 To fileCount
        For j = i + 1 To fileCount
            If targetFiles(i).SortKey > targetFiles(j).SortKey Then
                '要素を入れ替え
                tempInfo = targetFiles(i)
                targetFiles(i) = targetFiles(j)
                targetFiles(j) = tempInfo
            End If
        Next j
    Next i

    '== 3. 一時的な名前に一括リネーム(名前の衝突回避のため) ==
    For i = 1 To fileCount
        targetFiles(i).FileObject.Name = "temp_rename_" & i & ".tmp"
    Next i
    
    '== 4. 最終的な連番にリネームします ==
    For i = 1 To fileCount
        ' ここでは "Photo_001.jpg" という形式で名前を生成
        Dim finalName As String
        finalName = "Photo_" & Format(i, "000") & "." & fileExtension
        
        ' FSOのオブジェクトは名前を変えると実体参照が切れることがあるため、パスから再取得してリネーム
        objFSO.GetFile(targetFolder.Path & "¥" & "temp_rename_" & i & ".tmp").Name = finalName
    Next i

    MsgBox fileCount & "個のファイルをリネームしました。", vbInformation
    
    '== オブジェクトを解放します ==
    Set objFSO = Nothing
    Set targetFolder = Nothing

End Sub

コードの解説

  1. Private Type FileInfo ... End Type 複数の情報(ここではファイルオブジェクトと更新日時)をひとまとめにして扱うための「設計図」を定義しています。これを配列にすることで、ファイルの並べ替えが容易になります。
  2. ファイル情報の収集ループ targetFolder.Filesでフォルダ内の全ファイルを取得し、GetExtensionNameで拡張子を判定。対象ファイルが見つかったら、ReDim Preserveで配列のサイズを広げながら、ファイルオブジェクトと更新日時(DateLastModified)を格納していきます。
  3. 並べ替え(ソート)処理 ここでは理解しやすい「バブルソート」というアルゴリズムで配列を並べ替えています。targetFiles(i).SortKey(更新日時)を比較し、順序が逆であれば配列内の要素を丸ごと入れ替えます。
  4. 一時リネーム処理 "temp_rename_1.tmp" のように、絶対に重複しないであろう名前に一旦すべてのファイルを変更します。これにより、次の最終リネーム処理で名前の衝突が起こる心配がなくなります。
  5. 最終リネーム処理 Format(i, "000") の部分で、連番を「1→001」「12→012」のような3桁ゼロ埋めの文字列に変換しています。"Photo_" の部分や桁数を変更すれば、好きな形式のファイル名を作成できます。

まとめ

今回は、FSOを使って複数ファイルを一括で連番リネームするという、実用的ながら少し複雑な処理をご紹介しました。

  • ユーザー定義型(Type) を使うと、関連する情報をまとめて管理しやすくなる。
  • リネーム処理では、名前の衝突を避けるために一時ファイル名へリネームする工程を挟むと安全。
  • ソートのキー(今回は DateLastModified)を変更すれば、「作成日順」や「ファイル名順」など、様々なルールで連番を振ることが可能。

このテクニックを応用すれば、面倒なファイル整理作業を劇的に効率化できます。ぜひご自身の業務や趣味のファイル管理に役立ててみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次