- 技術 💻
VBAファイル・フォルダ操作|DirとFileSystemObject早見表
VBAでファイルやフォルダを操作する方法は、VBAに最初から入っている命令(Dir・MkDir・FileCopy・Name・Kill・RmDir)を使う方法と、FileSystemObject(FSO)を使う方法の2つです。 単体のファイルを1つ扱うだけなら標準の命令が短く書け、サブフォルダをたどる・フォルダごとコピーする・更新日時やサイズを調べるといった操作は FileSystemObject が向いています。
この記事では、存在確認・一覧取得・作成・コピー・移動・名前変更・削除の7つの操作を、2つの方法で並べた対応早見表と、そのまま貼れるコードで整理します。
確認環境:Windows 版 Excel の VBA を前提に、ファイル操作の命令とメソッドの構文・引数・注意書きを Microsoft Learn の VBA リファレンス(2026年10月5日閲覧)と照合して書いています。コードは標準モジュールに貼る形で、画面の出力例は載せていません。パスの C:\work は、手元のフォルダーに置き換えてください。
VBA標準とFileSystemObjectの対応早見表
fso は FileSystemObject の変数です(作り方は次の章)。
| 操作 | VBA標準 | FileSystemObject |
|---|---|---|
| ファイルの存在確認 | Dir(パス) <> "" |
fso.FileExists(パス) |
| フォルダーの存在確認 | (GetAttr(パス) And vbDirectory) = vbDirectory |
fso.FolderExists(パス) |
| ファイル一覧の取得 | Dir(パス\*.xlsx) → Dir() を繰り返す |
For Each f In fso.GetFolder(パス).Files |
| サブフォルダーの一覧 | Dir(パス\*, vbDirectory) と GetAttr |
For Each d In fso.GetFolder(パス).SubFolders |
| フォルダーの作成 | MkDir パス |
fso.CreateFolder パス |
| ファイルのコピー | FileCopy 元, 先 |
fso.CopyFile 元, 先, 上書き |
| フォルダーのコピー | (該当する命令なし) | fso.CopyFolder 元, 先, 上書き |
| ファイルの移動 | Name 元 As 先 |
fso.MoveFile 元, 先 |
| フォルダーの移動 | Name 元 As 先(同じドライブ内) |
fso.MoveFolder 元, 先 |
| 名前の変更 | Name 元 As 先 |
fso.GetFile(パス).Name = "新しい名前" |
| ファイルの削除 | Kill パス |
fso.DeleteFile パス, 強制 |
| フォルダーの削除 | RmDir パス(空のフォルダーのみ) |
fso.DeleteFolder パス, 強制(中身ごと) |
| 拡張子の取り出し | (文字列関数で切り出す) | fso.GetExtensionName(パス) |
| 更新日時・サイズ | - | f.DateLastModified、f.Size |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBAファイル・フォルダ操作|DirとFileSystemObject早見表」
FileSystemObjectの準備(参照設定とCreateObject)
FileSystemObject を使う書き方は2通りあります。
CreateObjectで作る(設定なしで動く書き方)
Sub UseFsoLateBinding()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
MsgBox fso.FolderExists("C:\work")
End Sub
参照設定をして型を指定する
VBE の[ツール]→[参照設定]で「Microsoft Scripting Runtime」にチェックを入れると、型を指定して宣言できます。
Sub UseFsoEarlyBinding()
Dim fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
MsgBox fso.FolderExists("C:\work")
End Sub
| 比べる点 | CreateObject | 参照設定 |
|---|---|---|
| 事前の設定 | 不要 | ブックごとに参照設定が必要 |
| 宣言 | Dim fso As Object |
Dim fso As Scripting.FileSystemObject |
| 入力候補の表示 | 出ない | 出る |
| 向いている場面 | ほかの人に配るブック | 自分で書き進めるとき |
この記事のコードは、貼るだけで使えるように CreateObject の形で統一しています。 参照設定をした場合は、As Object を As Scripting.FileSystemObject、As Scripting.Folder、As Scripting.File に置き換えられます。
存在を確認する
ファイルがあるか
' VBA標準
Function FileExistsStd(ByVal filePath As String) As Boolean
FileExistsStd = (Dir(filePath) <> "")
End Function
' FileSystemObject
Function FileExistsFso(ByVal filePath As String) As Boolean
FileExistsFso = CreateObject("Scripting.FileSystemObject").FileExists(filePath)
End Function
Dir は、見つかったファイルの名前を返し、見つからないときは長さ0の文字列("")を返します。
フォルダーがあるか
' VBA標準:GetAttr の戻り値にフォルダーの属性が含まれるかを調べる
Function FolderExistsStd(ByVal folderPath As String) As Boolean
On Error Resume Next
FolderExistsStd = ((GetAttr(folderPath) And vbDirectory) = vbDirectory)
On Error GoTo 0
End Function
' FileSystemObject
Function FolderExistsFso(ByVal folderPath As String) As Boolean
FolderExistsFso = CreateObject("Scripting.FileSystemObject").FolderExists(folderPath)
End Function
GetAttr は属性の合計値を返すので、And vbDirectory でフォルダーの属性(16)が立っているかを取り出します。パスが存在しないとエラーになるため、On Error Resume Next で受けて False のまま返しています。FolderExists は True か False を返すだけなので、エラー処理なしで書けます。
ファイル一覧を取得する
1つのフォルダーの中だけを一覧にする
アクティブシートの A 列にファイル名を書き出します。
' VBA標準:Dir を繰り返す
Sub ListFilesDir()
Const FOLDER_PATH As String = "C:\work\data"
Dim fileName As String
Dim r As Long
r = 1
fileName = Dir(FOLDER_PATH & "\*.xlsx")
Do While fileName <> ""
Cells(r, 1).Value = fileName
r = r + 1
fileName = Dir() ' 引数なしで次のファイル名を取り出す
Loop
End Sub
' FileSystemObject:Files コレクションを For Each で回す
Sub ListFilesFso()
Const FOLDER_PATH As String = "C:\work\data"
Dim fso As Object, f As Object
Dim r As Long
Set fso = CreateObject("Scripting.FileSystemObject")
r = 1
For Each f In fso.GetFolder(FOLDER_PATH).Files
If LCase$(fso.GetExtensionName(f.Name)) = "xlsx" Then
Cells(r, 1).Value = f.Name
Cells(r, 2).Value = f.Size
Cells(r, 3).Value = f.DateLastModified
r = r + 1
End If
Next f
End Sub
| 比べる点 | Dir | FileSystemObject |
|---|---|---|
| 絞り込み | パスにワイルドカード(*、?)を書く |
Files は全ファイルを返すので、If で絞る |
| 返ってくるもの | ファイル名の文字列 | File オブジェクト(Name・Path・Size・DateLastModified など) |
| 次の1件 | Dir() を引数なしで呼ぶ |
For Each が順に取り出す |
| 隠しファイル | 属性の引数(vbHidden など)で指定 | Files に含まれる |
| フォルダーが無いとき | "" が返る |
GetFolder でエラーになる |
GetFolder は、指定したフォルダーが無いとエラーになります。先に FolderExists で確かめておくと、メッセージを自分で決められます。
拡張子で絞り込む
' 複数の拡張子を対象にする(FileSystemObject)
Function IsTargetExt(ByVal fso As Object, ByVal fileName As String) As Boolean
Select Case LCase$(fso.GetExtensionName(fileName))
Case "xlsx", "xlsm", "csv"
IsTargetExt = True
End Select
End Function
GetExtensionName は、ピリオドを含まない拡張子の文字列を返します。大文字の拡張子(.XLSX)も拾えるように、LCase$ で小文字にそろえてから比べています。
Dir のワイルドカードで絞ったうえで拡張子を厳密にそろえたいときは、取り出した名前をもう一度確かめる条件を足します。
If LCase$(Right$(fileName, 5)) = ".xlsx" Then
' .xlsx で終わる名前だけを処理する
End If
サブフォルダーも再帰でたどる(FileSystemObject)
フォルダーの中のファイルを書き出したあと、SubFolders の1つひとつについて同じプロシージャを呼び直します。
Sub ListFilesRecursiveFso()
Const ROOT_PATH As String = "C:\work\data"
Dim fso As Object
Dim r As Long
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(ROOT_PATH) Then
MsgBox "フォルダーが見つかりません:" & ROOT_PATH
Exit Sub
End If
Range("A1:D1").Value = Array("パス", "ファイル名", "サイズ", "更新日時")
r = 2
WalkFolderFso fso, fso.GetFolder(ROOT_PATH), "xlsx", r
End Sub
' ext に "" を渡すと、すべてのファイルを対象にする
Private Sub WalkFolderFso(ByVal fso As Object, ByVal fld As Object, _
ByVal ext As String, ByRef r As Long)
Dim f As Object
Dim subFld As Object
For Each f In fld.Files
If ext = "" Or LCase$(fso.GetExtensionName(f.Name)) = LCase$(ext) Then
Cells(r, 1).Value = f.Path
Cells(r, 2).Value = f.Name
Cells(r, 3).Value = f.Size
Cells(r, 4).Value = f.DateLastModified
r = r + 1
End If
Next f
For Each subFld In fld.SubFolders
WalkFolderFso fso, subFld, ext, r ' 自分自身を呼び直す
Next subFld
End Sub
行番号 r は ByRef で渡しているので、呼び直した先で進んだ行がそのまま引き継がれます。
サブフォルダーも再帰でたどる(Dir)
Microsoft Learn の Dir 関数のページには、Dir を再帰的に呼び出すことはできないと書かれています。Dir は「前回の続き」を1つだけ覚えているため、繰り返しの途中で別のフォルダーに対して Dir を呼ぶと、元の続きが取り出せなくなります。そこで、サブフォルダーの名前を先に Collection にためて、Dir の繰り返しが終わってから1つずつたどります。
Sub ListFilesRecursiveDir()
Dim r As Long
r = 1
WalkFolderDir "C:\work\data", "*.xlsx", r
End Sub
Private Sub WalkFolderDir(ByVal folderPath As String, ByVal pattern As String, _
ByRef r As Long)
Dim itemName As String
Dim subFolders As Collection
Dim v As Variant
' 1) このフォルダーのファイルを書き出す
itemName = Dir(folderPath & "\" & pattern)
Do While itemName <> ""
Cells(r, 1).Value = folderPath & "\" & itemName
r = r + 1
itemName = Dir()
Loop
' 2) サブフォルダーの名前を先に集める
Set subFolders = New Collection
itemName = Dir(folderPath & "\*", vbDirectory)
Do While itemName <> ""
If itemName <> "." And itemName <> ".." Then
If (GetAttr(folderPath & "\" & itemName) And vbDirectory) = vbDirectory Then
subFolders.Add itemName
End If
End If
itemName = Dir()
Loop
' 3) Dir の繰り返しが終わってから、サブフォルダーをたどる
For Each v In subFolders
WalkFolderDir folderPath & "\" & v, pattern, r
Next v
End Sub
「.」「..」という名前が返る場合に備えて除外し、GetAttr でフォルダーかどうかを確かめてから Collection に入れています。
フォルダーを作成する
' VBA標準
Sub MakeFolderStd()
Const FOLDER_PATH As String = "C:\work\output"
If Dir(FOLDER_PATH, vbDirectory) = "" Then
MkDir FOLDER_PATH
End If
End Sub
' FileSystemObject
Sub MakeFolderFso()
Const FOLDER_PATH As String = "C:\work\output"
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(FOLDER_PATH) Then
fso.CreateFolder FOLDER_PATH
End If
End Sub
CreateFolder は、同じ名前のフォルダーがすでにあるとエラーになります。作成の前に存在確認を入れておくと、2回目以降の実行でもそのまま通ります。
途中の階層もまとめて作る
C:\work\2026\10\output のように、途中のフォルダーがまだ無い場合は、親フォルダーから順に作ります。
' 親フォルダーが無ければ先に作る(再帰)
Sub EnsureFolder(ByVal folderPath As String)
Dim fso As Object
Dim parentPath As String
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(folderPath) Then Exit Sub
parentPath = fso.GetParentFolderName(folderPath)
If parentPath <> "" Then
If Not fso.FolderExists(parentPath) Then EnsureFolder parentPath
End If
fso.CreateFolder folderPath
End Sub
使い方:EnsureFolder "C:\work\2026\10\output"
ファイルやフォルダーをコピーする
' VBA標準:コピー先はファイル名まで書く
Sub CopyFileStd()
FileCopy "C:\work\data\report.xlsx", "C:\work\backup\report.xlsx"
End Sub
' FileSystemObject:3つ目の引数で上書きするかを指定(省略時は True)
Sub CopyFileFso()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
' 1つのファイルを、名前を変えてコピー(同名があれば止める)
fso.CopyFile "C:\work\data\report.xlsx", "C:\work\backup\report_copy.xlsx", False
' ワイルドカードで複数のファイルを、既存のフォルダーへコピー
fso.CopyFile "C:\work\data\*.xlsx", "C:\work\backup\"
' フォルダーを中身ごとコピー
fso.CopyFolder "C:\work\data", "C:\work\backup\data"
End Sub
| 項目 | FileCopy | fso.CopyFile | fso.CopyFolder |
|---|---|---|---|
| 対象 | ファイル1つ | ファイル(ワイルドカード可) | フォルダー(中身ごと) |
| 上書きの指定 | 引数なし | 3つ目の引数(省略時 True) | 3つ目の引数(省略時 True) |
| 開いているファイル | エラーになる | - | - |
| ワイルドカード | - | コピー元の最後の要素にだけ書ける | コピー元の最後の要素にだけ書ける |
CopyFile のコピー先の末尾に \ を付けると「既存のフォルダーの中へ」、付けないと「その名前のファイルとして」扱われます。 コピー元にワイルドカードを使ったときは、コピー先はフォルダーとして扱われます。上書きを False にして同名のファイルがあるとエラーになり、コピー先が読み取り専用のときは上書きの指定にかかわらずエラーになります。
日付入りの名前でバックアップを取る例:
Sub BackupWithDate()
Const SRC As String = "C:\work\data\report.xlsx"
Dim fso As Object
Dim dst As String
Set fso = CreateObject("Scripting.FileSystemObject")
dst = "C:\work\backup\" & fso.GetBaseName(SRC) & "_" & _
Format$(Date, "yyyymmdd") & "." & fso.GetExtensionName(SRC)
If fso.FileExists(SRC) Then
fso.CopyFile SRC, dst, False
End If
End Sub
移動する・名前を変える
VBA標準では、移動も名前の変更も Name ステートメント1つで行います。
' VBA標準
Sub RenameAndMoveStd()
' 同じフォルダーの中で名前を変える
Name "C:\work\data\old.xlsx" As "C:\work\data\new.xlsx"
' 別のフォルダーへ移動する(同時に名前も変えられる)
Name "C:\work\data\new.xlsx" As "C:\work\done\new_done.xlsx"
' フォルダーの名前を変える
Name "C:\work\done" As "C:\work\finished"
End Sub
' FileSystemObject
Sub RenameAndMoveFso()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
' 名前を変える:File オブジェクトの Name に新しい名前を入れる
fso.GetFile("C:\work\data\old.xlsx").Name = "new.xlsx"
' 別のフォルダーへ移動する
fso.MoveFile "C:\work\data\new.xlsx", "C:\work\done\new.xlsx"
' 複数のファイルをまとめて移動する(移動先は既存のフォルダー)
fso.MoveFile "C:\work\data\*.csv", "C:\work\done\"
' フォルダーを移動する
fso.MoveFolder "C:\work\done", "C:\work\archive\done"
End Sub
| 項目 | Name ステートメント | fso.MoveFile/Name プロパティ |
|---|---|---|
| 名前の変更 | Name 元 As 先(フルパスで書く) |
fso.GetFile(パス).Name = "新しい名前"(名前だけ書く) |
| ファイルの移動 | できる(ドライブをまたいでもよい) | fso.MoveFile 元, 先 |
| フォルダー | 同じドライブの中での名前変更 | fso.MoveFolder 元, 先、Folder の Name プロパティ |
| ワイルドカード | 使えない | 移動元の最後の要素にだけ書ける |
| 移動先に同名がある | 指定できない(先の名前は存在していないこと) | エラーになる |
| 開いているファイル | エラーになる(閉じてから実行) | - |
FileSystemObject には「Rename」という名前のメソッドはなく、File や Folder の Name プロパティに新しい名前を代入します。Name プロパティには、パスを含めずに名前だけを書きます。
同名があるときに連番を付けて移動する例:
Sub MoveWithoutOverwrite()
Const SRC As String = "C:\work\data\report.xlsx"
Const DST_FOLDER As String = "C:\work\done"
Dim fso As Object
Dim dst As String
Dim n As Long
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(SRC) Then Exit Sub
dst = fso.BuildPath(DST_FOLDER, fso.GetFileName(SRC))
Do While fso.FileExists(dst)
n = n + 1
dst = fso.BuildPath(DST_FOLDER, fso.GetBaseName(SRC) & "_" & n & _
"." & fso.GetExtensionName(SRC))
Loop
fso.MoveFile SRC, dst
End Sub
削除する
' VBA標準
Sub DeleteStd()
Kill "C:\work\temp\old.csv" ' ファイルを1つ削除
Kill "C:\work\temp\*.tmp" ' ワイルドカードでまとめて削除
RmDir "C:\work\temp" ' 空のフォルダーを削除
End Sub
' FileSystemObject
Sub DeleteFso()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile "C:\work\temp\old.csv" ' ファイルを1つ削除
fso.DeleteFile "C:\work\temp\*.tmp", True ' 読み取り専用も含めて削除
fso.DeleteFolder "C:\work\temp" ' フォルダーを中身ごと削除
End Sub
| 項目 | Kill | RmDir | fso.DeleteFile | fso.DeleteFolder |
|---|---|---|---|---|
| 対象 | ファイル | フォルダー | ファイル | フォルダー |
| ワイルドカード | 使える | - | 最後の要素にだけ書ける | 最後の要素にだけ書ける |
| 中身のあるフォルダー | - | エラーになる(先に Kill で中のファイルを削除) | - | 中身ごと削除する |
| 読み取り専用 | - | - | 2つ目の引数を True にすると削除 | 2つ目の引数を True にすると削除 |
| 対象が1つも無いとき | エラー53 | - | エラーになる | エラーになる |
| 開いているファイル | エラーになる | - | - | - |
DeleteFolder は、フォルダーに中身があるかどうかを区別せずに削除します。 対象のパスを変数で組み立てるときは、次の「On Error 付きの削除」のように、実行前の確認を入れておくと安心です。
On Error付きで安全に削除する
存在しないファイルを Kill するとエラー53、開いているファイルを Kill するとエラーになります。「あれば消す。消せなかったら理由を残して先へ進む」形にしておくと、処理全体が途中で止まりません。
' 削除できたら True、できなかったら False を返す
Function SafeDeleteFile(ByVal filePath As String) As Boolean
On Error GoTo ErrHandler
' ワイルドカードを含むパスは、この関数では受け付けない
If InStr(filePath, "*") > 0 Or InStr(filePath, "?") > 0 Then
Debug.Print "ワイルドカードは指定できません:" & filePath
Exit Function
End If
' 無ければ何もしない(削除済みと同じ扱い)
If Dir(filePath) = "" Then
SafeDeleteFile = True
Exit Function
End If
Kill filePath
SafeDeleteFile = True
Exit Function
ErrHandler:
Debug.Print "削除できませんでした:" & filePath & _
" / エラー " & Err.Number & ":" & Err.Description
SafeDeleteFile = False
End Function
呼び出す側:
Sub DeleteOldFiles()
Dim targets As Variant, t As Variant
Dim ngCount As Long
targets = Array("C:\work\temp\a.csv", "C:\work\temp\b.csv", "C:\work\temp\c.csv")
For Each t In targets
If Not SafeDeleteFile(CStr(t)) Then ngCount = ngCount + 1
Next t
If ngCount > 0 Then
MsgBox ngCount & " 件は削除できませんでした。イミディエイトウィンドウを確認してください。"
End If
End Sub
削除の代わりに退避フォルダーへ移動する
すぐに消さず、退避用のフォルダーへ移してから、後でまとめて削除する形です。
Sub MoveToTrashFolder()
Const SRC As String = "C:\work\temp\old.csv"
Const TRASH As String = "C:\work\_trash"
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FileExists(SRC) Then Exit Sub
If Not fso.FolderExists(TRASH) Then fso.CreateFolder TRASH
fso.MoveFile SRC, fso.BuildPath(TRASH, _
Format$(Now, "yyyymmdd_hhnnss") & "_" & fso.GetFileName(SRC))
End Sub
中身を確認してからフォルダーを削除する
Sub DeleteFolderAfterConfirm()
Const TARGET As String = "C:\work\temp"
Dim fso As Object, fld As Object, f As Object
Dim listText As String
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(TARGET) Then Exit Sub
Set fld = fso.GetFolder(TARGET)
For Each f In fld.Files ' 中のファイル名を並べる
listText = listText & f.Name & vbCrLf
Next f
If MsgBox(TARGET & " を中身ごと削除します。" & vbCrLf & listText, _
vbOKCancel + vbExclamation) = vbOK Then
fso.DeleteFolder TARGET
End If
End Sub
実行時エラー53・70・75・76の原因表
Microsoft Learn の各エラーのページに書かれている原因を、ファイル操作に関係するものに絞って整理しました。
| 番号 | 公式ページの見出し(意味) | 公式ページに書かれている原因 | 対応 |
|---|---|---|---|
| 53 | File not found(ファイルが見つからない) | Kill、Name、Open などが、存在しないファイルを指している | ファイル名とパスのつづりを確かめる。実行前に Dir や FileExists で存在確認をする |
| 70 | Permission denied(アクセスが許可されていない) | 書き込み禁止のファイルやディスクに書き込もうとした。ほかのプロセスがロックしているファイルに書き込もうとした | ファイルを開いているアプリを閉じる。読み取り専用の属性を確かめる |
| 75 | Path/File access error(パスやファイルにアクセスできない) | ファイルの指定の形式が正しくない。読み取り専用のファイルを置き換える保存をしようとした。Open・MkDir・ChDir・RmDir などで、パスとファイル名を結び付けられない | パスの書き方(ドライブ名、区切りの \、絶対パスか相対パスか)を見直す。読み取り専用の属性を確かめる |
| 76 | Path not found(パスが見つからない) | Open・MkDir・ChDir・RmDir などで、指定したパスが見つからない | 途中のフォルダーが存在するかを確かめる。無ければ親から順に作る |
この記事の操作とエラーの関係
| 操作 | エラーになる条件(公式の注意書き) | 先に入れておく確認 |
|---|---|---|
Kill |
存在しないファイル(53)、開いているファイル | Dir(パス) <> "" |
Name |
元のファイルが無い(53)、先の名前がすでにある、開いているファイル | 元は存在、先は存在しないことを確認 |
FileCopy |
開いているファイル | コピー元を閉じてから実行 |
MkDir |
指定したパスが見つからない(76) | 親フォルダーの存在確認 |
RmDir |
フォルダーの中にファイルがある、パスが見つからない(76) | 先に中のファイルを Kill |
fso.CreateFolder |
同じ名前のフォルダーがある | fso.FolderExists |
fso.GetFolder |
フォルダーが無い | fso.FolderExists |
fso.CopyFile |
上書き False で同名あり、コピー先が読み取り専用、ワイルドカードに一致なし | fso.FileExists |
fso.MoveFile |
移動先に同名のファイルがある、ワイルドカードに一致なし | fso.FileExists |
fso.DeleteFile/DeleteFolder |
一致する対象が無い | fso.FileExists/fso.FolderExists |
FileSystemObject のメソッドは、ワイルドカードで複数を処理している途中でエラーになると、そこで止まり、それまでに行った変更は元に戻りません(CopyFile・MoveFile・DeleteFile・DeleteFolder の各ページの注意書き)。件数が多いときは、For Each で1件ずつ処理してエラーを記録する形にすると、どこまで進んだかを追えます。
エラー番号で処理を分ける定型
Sub MoveReportWithErrorHandling()
Const SRC As String = "C:\work\data\report.xlsx"
Const DST As String = "C:\work\done\report.xlsx"
On Error GoTo ErrHandler
Name SRC As DST
MsgBox "移動しました。"
Exit Sub
ErrHandler:
Select Case Err.Number
Case 53
MsgBox "移動元のファイルが見つかりません:" & SRC
Case 70
MsgBox "ファイルが使用中か、書き込みが許可されていません。"
Case 75, 76
MsgBox "パスを確認してください:" & DST
Case Else
MsgBox "エラー " & Err.Number & ":" & Err.Description
End Select
End Sub
Case Else で番号と説明をそのまま表示しておくと、想定していなかったエラーの手がかりが残ります。
DirとFileSystemObjectの選び方
| 状況 | 選ぶ方法 | 理由 |
|---|---|---|
| ファイルが1つあるかを確かめる | Dir | 1行で書ける |
| 1つのフォルダーの中を、ワイルドカードで絞って一覧にする | Dir | パスに *.xlsx と書くだけで絞れる |
| サブフォルダーもたどる | FileSystemObject | SubFolders を For Each で回せる。Dir は再帰的に呼べないため工夫が要る |
| 更新日時・サイズ・拡張子を使う | FileSystemObject | File オブジェクトのプロパティで取れる |
| フォルダーを中身ごとコピー・削除する | FileSystemObject | CopyFolder・DeleteFolder がある |
| ファイルの名前変更・移動だけ | Name ステートメント | 1行で書ける |
| 上書きするかどうかを指定してコピーする | FileSystemObject | CopyFile の3つ目の引数で決められる |
| 途中の階層もまとめてフォルダーを作る | FileSystemObject | GetParentFolderName で親をたどれる |
2つの方法は同じプロシージャの中で混ぜて使えます。存在確認は Dir、一覧と再帰は FileSystemObject、名前変更は Name、という組み合わせでも問題ありません。
よくある質問
Q. FileSystemObjectでファイル名を変更するメソッドはどれですか?
A. 名前変更用のメソッドはなく、fso.GetFile(パス).Name = "新しい名前" のように、File オブジェクトの Name プロパティへ代入します。フォルダーも同じく Folder オブジェクトの Name プロパティで変えられます。VBA標準なら Name 元 As 先 です。
Q. 参照設定とCreateObjectは、どちらで書けばよいですか? A. ほかの人に渡すブックは、設定なしで動く CreateObject が向いています。自分で書き進めるときは、参照設定をすると入力候補が出て書きやすくなります。メソッドや引数は同じです。
Q. Dirでサブフォルダーの中まで一覧にできますか? A. できます。ただし Dir は再帰的に呼び出せないので、サブフォルダーの名前を Collection にためてから、Dir の繰り返しが終わった後でたどります(この記事の WalkFolderDir)。コードを短くしたいなら FileSystemObject の SubFolders が向いています。
Q. フォルダーを削除しようとするとエラーになります。
A. RmDir は、中にファイルがあるフォルダーには使えません。先に Kill で中のファイルを削除するか、中身ごと削除する fso.DeleteFolder を使います。パスが見つからない場合はエラー76になるので、存在確認を先に入れます。
まとめ
- ファイル操作は2系統:VBA標準(Dir・MkDir・FileCopy・Name・Kill・RmDir)と FileSystemObject。同じプロシージャで混ぜて使える
- 存在確認は
Dir(パス) <> ""かfso.FileExists/fso.FolderExists。操作の前に入れると、エラーを先回りできる - 一覧取得は、1フォルダーなら Dir とワイルドカード、サブフォルダーまでたどるなら FileSystemObject の Files と SubFolders
- Dir は再帰的に呼べないので、サブフォルダー名を Collection にためてからたどる
- 移動と名前変更は Name ステートメント1つ。FileSystemObject では MoveFile と、File・Folder の Name プロパティ
- 削除は Kill(ファイル)と RmDir(空のフォルダー)。中身ごと消すなら DeleteFolder で、実行前の確認を入れる
- エラー53・70・75・76 は、ファイルが無い/使用中・書き込み不可/パスの形式/パスが見つからない、の順に切り分ける
参考・出典
- Microsoft Learn「Dir function」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/dir-function
- Microsoft Learn「MkDir statement」「FileCopy statement」「Name statement」「Kill statement」「RmDir statement」「GetAttr function」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/name-statement
- Microsoft Learn「FileSystemObject object」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object
- Microsoft Learn「CopyFile method」「MoveFile method」「DeleteFile method」「DeleteFolder method」「CreateFolder method」「CopyFolder method」「MoveFolder method」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/copyfile-method
- Microsoft Learn「Files property」「SubFolders property」「Name property (FileSystemObject object)」「File object」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/files-property
- Microsoft Learn「Format function」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/format-function-visual-basic-for-applications
- Microsoft Learn「File not found (Error 53)」「Permission denied (Error 70)」「Path/File access error (Error 75)」「Path not found (Error 76)」 https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/file-not-found-error-53
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBAファイル・フォルダ操作|DirとFileSystemObject早見表」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。