🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の FileSystemObject — CreateObject 対 参照設定、サブフォルダー、そしてなぜブックを開けないのか

|

Excel VBA の FileSystemObject — CreateObject 対 参照設定、サブフォルダー、そしてなぜブックを開けないのか

TL;DRFileSystemObject(FSO)はディスクのためのオブジェクトモデルです。一度作れば、 あとは FilesSubFolders をループし、SizeDateLastModified のようなプロパティを 読めます。遅延バインディングで作れば、参照設定にチェックを入れずにどのマシンでも動きます。

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 には端からできないこと
  • メタデータを読む — SizeDateLastModifiedNameParentFolder
  • FileExistsFolderExists動く前に確かめるためのきれいな方法
  • FSO がテキストファイルは開くのに、Excel のブックは決して開かない理由

考え方の軸:ディスクをオブジェクトモデルとして扱う

VBA のほかのどこでも、あなたはオブジェクトを相手にします — WorkbookSheets を持ち、 WorksheetRange を持つ。FileSystemObject は、その同じ考えをディスクへ拡張します。

  • fsoGetFolder(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 とその仲間たち(GetBaseNameBuildPathGetParentFolderName)にも注目してください — 面倒な 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

SizeDateLastModifiedDateCreatedTypeAttributes — どれもプロパティひとつぶんの 距離です。「今週変更されたブックすべて」の絞り込みや「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 ...

FileExistsFolderExists は別物です — Dir は両者をあいまいにします — だからあなたは自分の 意図をぴったり言い表せて、ファイルを調べたいのにうっかりフォルダーに一致してしまうことがありません。

落とし穴:FSO はブックを開かない

これが、人々を堂々巡りに追い込む混乱です。FileSystemObjectプレーンテキストファイルの作成・ 読み取り・書き込みCreateTextFileOpenTextFile)ができます — ログ、生のテキストとして扱う CSV、.ini ファイル。CopyFileMoveFileDeleteFile もできます。できないのは、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 のコンポーネントです — コレクション(FilesSubFolders)とプロパティ(NameSizeDateLastModified)を持つ 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 はテキストファイルの開閉・書き込み(OpenTextFileCreateTextFile)ができ、 どんなファイルでもコピー・移動・削除できますが、ブックは開けません。ファイルを見つけるのに 使い、それから各ファイルを Workbooks.Open で開きましょう。.xlsx に対する fso.OpenTextFile は、ブックではなく生のバイト列を返します。

VBA でファイルのサイズや更新日を得るには?

FileSystemObject を使います:fso.GetFile(path).Size はバイト数を、.DateLastModified は タイムスタンプを返します。フォルダーループの中では、各 File オブジェクトに対して file.Sizefile.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