TL;DR —
FileSystemObject(FSO)はディスクのためのオブジェクトモデルです。一度作れば、 あとはFilesとSubFoldersをループし、SizeやDateLastModifiedのようなプロパティを 読めます。遅延バインディングで作れば、参照設定にチェックを入れずにどのマシンでも動きます。
Sub ListWithSizes()
Dim fso As Object, folder As Object, file As Object
Set fso = CreateObject("Scripting.FileSystemObject") ' 遅延バインディング — 参照設定は不要
Set folder = fso.GetFolder("C:\Reports")
For Each file In folder.Files ' カーソルではなく本物のコレクション
Debug.Print file.Name, file.Size, file.DateLastModified
Next file
End Sub
Dir が隠れたカーソルをひとつ持つ簡潔な組み込みであるのに対して、
FileSystemObject はファイルシステムを、VBA のほかの部分がブックを扱うのと同じように扱います —
ループして調べられる、プロパティを持ったオブジェクトとして。それが、この道具で手に入るもの
です。サブフォルダー、ファイルのメタデータ、安全な入れ子ループ。代償は、作るべきオブジェクトが
ひとつ、そして判断がひとつ — どうバインドするか — で、その判断が、あなたのマクロが他人のパソコン
でも動くかどうかを静かに決めます。
この記事で学べること
- 考え方の軸 — ファイルシステムを、それぞれプロパティを持つフォルダーとファイルとして見る
- 誰もがつまずくたった一つの判断 —
CreateObject(遅延バインディング)対Dim … As New(事前バインディング) - サブフォルダーへの再帰の方法、
Dirには端からできないこと - メタデータを読む —
Size、DateLastModified、Name、ParentFolder FileExistsとFolderExists— 動く前に確かめるためのきれいな方法- FSO がテキストファイルは開くのに、Excel のブックは決して開かない理由
考え方の軸:ディスクをオブジェクトモデルとして扱う
VBA のほかのどこでも、あなたはオブジェクトを相手にします — Workbook は Sheets を持ち、
Worksheet は Range を持つ。FileSystemObject は、その同じ考えをディスクへ拡張します。
fsoはGetFolder(path)とGetFile(path)を与えてくれるFolderは.Filesコレクション、.SubFoldersコレクション、そして.Nameを持つFileは.Name、.Size、.DateLastModified、.ParentFolder、.Pathを持つ
だからカーソルを仕込んでは進める代わりに、あなたはすでに知っているループを書きます —
For Each file In folder.Files — そして各オブジェクトに手を入れて、必要なものを取り出します。
隠れた状態がないので、ループを自由に入れ子にできます(サブフォルダーの中のサブフォルダーの中の
ファイル)。下で何かがリセットされる心配はありません。
誰もがつまずくたった一つの判断:CreateObject 対 New
fso を作る方法は 2 つあり、その違いが、あなたのマクロが同僚にメールで送られても生き残れるかを
決めます。これがナンバーワンの FileSystemObject バグです。
事前バインディング — 見た目はきれいだが、もろい。
Dim fso As New FileSystemObject ' [ツール] > [参照設定] > Microsoft Scripting Runtime が必要
これは、そのマシンで Microsoft Scripting Runtime の参照にチェックが入っている場合にのみ
コンパイルできます。チェックの入ったあなたの PC で書き、チェックの入っていない誰かへファイルを
送ると、1 行も走る前に User-defined type not defined(ユーザー定義型が定義されていません)で
コンパイルに失敗します。引き換えに IntelliSense は手に入りますが、ブックを 1 台のマシンの設定に
縛りつけてしまったのです。
遅延バインディング — 可搬性のある既定。
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject") ' 実行時に解決、参照設定なし
CreateObject はコンポーネントを名前で実行時に探すので、参照設定は不要で、Windows Scripting
がインストールされているところ(つまりどこでも)ならブックは動きます。コンパイル時の IntelliSense
は失いますが、配布したときにただ動くマクロが手に入ります。共有するものには、遅延バインディング
を使い、変数を As Object で宣言しましょう。そのたった一つの選択が、「私のマシンでは動く」報告の
クラス全体を取り除きます。
サブフォルダー:Dir にできないこと
Dir を置いていく最も明快な理由は、フォルダーのツリーです。FSO の SubFolders コレクションと
再帰的な Sub があれば、どんな深さでも歩けます。Dir の単一カーソルには不可能なことです。
Sub WalkTree(folderPath As String)
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
ProcessFolder fso.GetFolder(folderPath), fso
End Sub
Sub ProcessFolder(fld As Object, fso As Object)
Dim file As Object, sub_ As Object
For Each file In fld.Files
If LCase(fso.GetExtensionName(file.Name)) = "xlsx" Then Debug.Print file.Path
Next file
For Each sub_ In fld.SubFolders ' 再帰 — Dir はこんな入れ子はできない
ProcessFolder sub_, fso
Next sub_
End Sub
Folder はそれぞれ自分の .Files と .SubFolders を持つので、入れ子と再帰は安全です —
壊れる共有カーソルがありません。fso.GetExtensionName とその仲間たち(GetBaseName、BuildPath、
GetParentFolderName)にも注目してください — 面倒な InStrRev の切り出しに取って代わる、
文字列いじりのいらないパスヘルパーです。
メタデータを読む:サイズ・日付・名前
FSO を選ぶもうひとつの理由は、File オブジェクトが Dir の決して見せない自分自身についての
情報を知っていることです。
For Each file In folder.Files
If file.DateLastModified < Now - 30 Then ' 30 日より古い
Debug.Print file.Name & " — " & Format(file.Size / 1024, "0") & " KB"
End If
Next file
Size、DateLastModified、DateCreated、Type、Attributes — どれもプロパティひとつぶんの
距離です。「今週変更されたブックすべて」の絞り込みや「10 MB を超える一時ファイルを削除」は、
FSO なら造作もなく、Dir なら苦痛です。
FileExists と FolderExists:動く前に確かめる
FSO は、ファイルの存在をテストする最もきれいな方法である、
状態を持たない 2 つの述語を与えてくれます — そして決定的なことに、これらには隠れたカーソルが
ありません。だから Dir とは違い、Dir ループの中も含めてどこでも呼べます。
If fso.FileExists("C:\Reports\March.xlsx") Then ...
If fso.FolderExists("C:\Reports\2026") Then ...
FileExists と FolderExists は別物です — Dir は両者をあいまいにします — だからあなたは自分の
意図をぴったり言い表せて、ファイルを調べたいのにうっかりフォルダーに一致してしまうことがありません。
落とし穴:FSO はブックを開かない
これが、人々を堂々巡りに追い込む混乱です。FileSystemObject はプレーンテキストファイルの作成・
読み取り・書き込み(CreateTextFile、OpenTextFile)ができます — ログ、生のテキストとして扱う
CSV、.ini ファイル。CopyFile、MoveFile、DeleteFile もできます。できないのは、Excel の
ブックを開くことです。
Set wb = fso.OpenTextFile("C:\Reports\March.xlsx") ' 誤り — ブックではなく生の XML/zip バイト列が返る
Set wb = Workbooks.Open("C:\Reports\March.xlsx") ' 正しい — ブックを開くのは FSO ではなく Excel
FSO はファイルを見つけて管理します。ファイルを、セルを読める生きたブックに変えるのは
Workbooks.Open です。定石のバッチマクロは両方を使います。FSO
(または Dir)でフォルダーを列挙し、それから Workbooks.Open で各結果を開く。この 2 つの
仕事を頭の中で分けておけば、パターン全体がかちりと噛み合います。
正直な結論:FSO が Dir に勝つとき
Dir が勝つのはただ 1 軸だけ — フラットな単一フォルダーのループを、準備ゼロで。FileSystemObject
はそれ以外のすべてで勝ち、その判断は機械的です。
- サブフォルダーが必要? FSO —
Dirは再帰できない。 - サイズ、日付、種類が必要? FSO —
Dirは名前しか返さない。 - コピー、移動、削除、テキストファイルの書き込み? FSO — 一式そろった道具箱。
- 何も足さない、単一フォルダーの手早い
*.xlsxループ?Dirで十分だし、短い。 - どう列挙しようと、ブックは
Workbooks.Openで開く — 決して FSO では開かない。
そしてどちらを配布するにせよ、オブジェクトは New ではなく**CreateObject** で作りましょう —
そうすれば、あなたのマシンだけでなく、どのマシンでも動きます。
ExcelMaster の活用
FileSystemObject が強力なのは、まさにそれがオブジェクトモデルだからです — しかしそれは、可搬性の
ために遅延バインディングにすること、ツリーのために SubFolders を再帰すること、正しいメタデータ
プロパティを読むこと、そして各ファイルを FSO で開こうとせず Workbooks.Open に手渡すことを、
覚えておかねばならないという意味でもあります。小さな選択の一つひとつが、そのマクロが次の人の
PC で動くかどうかを静かに決めます。
ExcelMaster は、その
選択を代わりに行います。タスクを説明すれば — 「Reports の下の全サブフォルダーをたどって、今月
変更されたブックを見つけて、その合計をサマリーにコピーして」 — 再帰的な SubFolders ループ、
DateLastModified フィルター、そしてヒットごとに対応する
Workbooks.Open / Close を備えた、
遅延バインディングの FSO ウォークを書きます。あなたは結果を説明するだけ。オブジェクトモデルを
一発で正しく組み上げるのは、それがやります。
よくある質問
VBA の FileSystemObject とは何ですか?
FileSystemObject(FSO)は、ファイルシステムをオブジェクトモデルとして公開する Windows Scripting
のコンポーネントです — コレクション(Files、SubFolders)とプロパティ(Name、Size、
DateLastModified)を持つ Folder オブジェクトと File オブジェクト。CreateObject("Scripting.FileSystemObject")
で作り、ファイルの列挙・コピー・移動・削除、そしてテキストファイルの読み書きに使います。
Dir と違って隠れたカーソルがないので、ループを安全に入れ子にできます。
CreateObject と Dim As New FileSystemObject、どちらを使うべきですか?
Set fso = CreateObject("Scripting.FileSystemObject")(遅延バインディング)を使いましょう。
参照設定が不要で、どのマシンでも動きます。Dim fso As New FileSystemObject(事前バインディング)は
[ツール] ▸ [参照設定] で Microsoft Scripting Runtime にチェックが入っている必要があり、あなたの
PC でコンパイルできるブックが、同僚のところでは User-defined type not defined(ユーザー定義型が
定義されていません)で失敗します。配布するものには、遅延バインディングが可搬性のある既定です。
FileSystemObject でサブフォルダーをループするには?
fso.GetFolder(path) でフォルダーを取得し、その .SubFolders コレクションをループして、各
サブフォルダーに対して同じルーチンを再帰的に呼びます。Folder はそれぞれ自分の .Files と
.SubFolders を持つので、再帰は安全です — リセットされる共有状態がありません。これこそ
Dir にできないことです。
FileSystemObject で Excel のブックを開けますか?
いいえ。FSO はテキストファイルの開閉・書き込み(OpenTextFile、CreateTextFile)ができ、
どんなファイルでもコピー・移動・削除できますが、ブックは開けません。ファイルを見つけるのに
使い、それから各ファイルを Workbooks.Open で開きましょう。.xlsx
に対する fso.OpenTextFile は、ブックではなく生のバイト列を返します。
VBA でファイルのサイズや更新日を得るには?
FileSystemObject を使います:fso.GetFile(path).Size はバイト数を、.DateLastModified は
タイムスタンプを返します。フォルダーループの中では、各 File オブジェクトに対して file.Size と
file.DateLastModified を直接読みます。Dir はどちらも与えられません — 名前しか返しません — これが、
フラットな一覧より先はすべて FSO を好む主な理由のひとつです。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-21。
関連ガイド: VBA Dir · VBA Check If File Exists · VBA Open Workbook · VBA Save Workbook · VBA On Error
