VBAでフォルダ内ファイル一括処理・リネーム・アーカイブ
💡 本編(VBAなし)との位置づけ
「複数ファイルの中身のデータを結合する」だけであればVBAは不要です。代替手法は → パワークエリ「データ取り込みパターン集」 を使用してください。本記事は、ファイル自体の「移動」「名前変更」を行うための手法です。
1. パワークエリの限界とFileSystemObject (FSO)
パワークエリの「フォルダーから」取り込みは、大量のCSVやExcelファイルのデータを一気に結合する際に強力ですが、「ファイル自体をリネームする」「処理が終わったファイルを別フォルダに移動(アーカイブ)する」といったファイルシステムへの干渉はできません。
業務フローとして「処理済みファイルは別フォルダへ退避する」ルールがある場合、VBAの FileSystemObject (FSO) が最も確実で安全な選択肢となります。標準の Name ステートメントや Dir 関数は古い仕様であり、Unicode文字の扱いや別ドライブへの移動でエラーを起こしやすいため、現代の実務ではFSO一択です。
2. 実践:Excelリストに基づく一括リネーム(FSO版)
A列に「現在のファイル名」、B列に「新しいファイル名」を入力したリスト(シート名:リネームリスト)を用意し、一気にリネームする堅牢なコードです。上書きエラーやファイル欠損を事前に検知します。
Sub FSO_ファイル一括リネーム()
Dim ws As Worksheet
Dim i As Long, lastRow As Long
Dim folderPath As String
Dim oldPath As String, newPath As String
Dim fso As Object
Dim successCount As Long, errorCount As Long
Set ws = ThisWorkbook.Sheets("リネームリスト")
Set fso = CreateObject("Scripting.FileSystemObject")
folderPath = ThisWorkbook.Path & "\TargetFolder\" ' 処理対象フォルダ
lastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
oldPath = fso.BuildPath(folderPath, ws.Cells(i, 1).Value)
newPath = fso.BuildPath(folderPath, ws.Cells(i, 2).Value)
' リネームの安全性チェック
If Not fso.FileExists(oldPath) Then
ws.Cells(i, 3).Value = "エラー:元ファイルなし"
errorCount = errorCount + 1
ElseIf fso.FileExists(newPath) Then
ws.Cells(i, 3).Value = "エラー:同名ファイルが存在"
errorCount = errorCount + 1
Else
' FSOによるリネーム(ファイルのNameプロパティを利用)
On Error Resume Next
fso.GetFile(oldPath).Name = ws.Cells(i, 2).Value
If Err.Number = 0 Then
ws.Cells(i, 3).Value = "完了"
successCount = successCount + 1
Else
ws.Cells(i, 3).Value = "エラー:ファイル使用中など"
End If
On Error GoTo 0
End If
Next i
Set fso = Nothing
MsgBox "処理完了" & vbCrLf & "成功: " & successCount & "件" & vbCrLf & "失敗: " & errorCount & "件", vbInformation
End Sub
3. 処理済みファイルのアーカイブ(日付別フォルダへ移動)
パワークエリでデータを読み込んだ後、使用したCSVファイルを「YYYYMM」形式のアーカイブフォルダに自動で移動させるルーチンです。
Sub 処理済ファイル_アーカイブ()
Dim fso As Object
Dim sourceFolder As String, archiveRoot As String, targetFolder As String
Dim f As Object, folderObj As Object
Dim yyyymm As String
Set fso = CreateObject("Scripting.FileSystemObject")
sourceFolder = ThisWorkbook.Path & "\ImportData\"
archiveRoot = ThisWorkbook.Path & "\Archive\"
' 今月のフォルダ名を生成(例:202604)
yyyymm = Format(Date, "yyyymm")
targetFolder = fso.BuildPath(archiveRoot, yyyymm)
' アーカイブのルート、および月別フォルダが存在しなければ作成
If Not fso.FolderExists(archiveRoot) Then fso.CreateFolder archiveRoot
If Not fso.FolderExists(targetFolder) Then fso.CreateFolder targetFolder
Set folderObj = fso.GetFolder(sourceFolder)
' フォルダ内の全CSVを移動
For Each f In folderObj.Files
If LCase(fso.GetExtensionName(f.Name)) = "csv" Then
' 移動先に同名ファイルがある場合は上書き(True指定)できる Copy を使い、その後削除
' ※ MoveFile は上書きできないため安全ですが、業務要件により選択してください
fso.CopyFile f.Path, fso.BuildPath(targetFolder, f.Name), True
f.Delete
End If
Next f
Set fso = Nothing
MsgBox "CSVファイルのアーカイブが完了しました。", vbInformation
End Sub
実務でのポイント:
MoveFile は移動先に同名ファイルが存在するとエラーになります。日次処理で再実行の可能性がある場合、CopyFile (Overwrite:=True) してから Delete する手法がトラブルになりにくい運用方法です。
4. サブフォルダも含む再帰処理
対象フォルダの中にさらにサブフォルダがある場合、再帰的に全てのファイルを処理するパターンです。月別フォルダの中にあるCSVを一括でリネームしたい場合などに使います。
Sub 再帰的ファイル一覧取得(folderPath As String, result As Collection)
Dim fso As Object, folder As Object, subFolder As Object, f As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(folderPath)
' 現在のフォルダ内のファイルを収集
For Each f In folder.Files
result.Add f.Path
Next f
' サブフォルダに対して再帰呼び出し
For Each subFolder In folder.SubFolders
再帰的ファイル一覧取得 subFolder.Path, result
Next subFolder
End Sub
' --- 使用例 ---
Sub テスト_再帰取得()
Dim files As New Collection
再帰的ファイル一覧取得 ThisWorkbook.Path & "\TargetFolder", files
Dim i As Long
For i = 1 To files.Count
Debug.Print files(i)
Next i
MsgBox files.Count & "件のファイルが見つかりました。", vbInformation
End Sub
5. パワークエリとの使い分けまとめ
| やりたいこと | パワークエリ(本編) | VBA FSO(この記事) |
|---|---|---|
| 複数CSVのデータを結合 | ✅ フォルダー取込で一発 | 不要(PQを使うべき) |
| ファイルのリネーム | ❌ 不可能 | ✅ FSO.GetFile.Name |
| 処理済ファイルを別フォルダに移動 | ❌ 不可能 | ✅ FSO.MoveFile / CopyFile |
| サブフォルダの再帰的探索 | △ フォルダー取込のみ | ✅ 再帰関数で自在に |