FileSystemObjectでフォルダ内のファイル一覧を取得する方法について解説します。
この処理はFileSystemObject(以下FSO)を扱う上での基本となるコードで、
とてもきれいなForEach文で書くことができます。
FSOを体系的に勉強したいという方は、まずはこの処理から学習していきましょう。
◇ FileSystemObject入門シリーズ
【1】FileSystemObjectとは - Dir関数群との違い
【2】参照設定と変数宣言
【3】ファイル一覧の取得(本記事)
【4】すべての下層フォルダの取得
【5】FileSystemObjectって何が便利なの?
フォルダ内のファイル一覧を取得する
フォルダ内のすべてのファイルを取得して、
その情報をシートに書き出すコードがこちらです。
ソースコード
Public FSO As New FileSystemObject Sub 指定フォルダのファイル一覧をシートに書き出す() ' 出力するシートを取得 Dim 出力シート As Worksheet Set 出力シート = Worksheets("ファイル一覧") Dim R As Long: R = 2 ' GetFolderメソッドでFolderオブジェクトを取得する Dim 指定フォルダ As Folder Set 指定フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\テスト") ' Filesプロパティの中をForEachで順次取得する Dim ファイル As File For Each ファイル In 指定フォルダ.Files ' ファイルの情報をシートに書き出す 出力シート.Cells(R, 1) = ファイル.Name 出力シート.Cells(R, 2) = ファイル.DateLastModified 出力シート.Cells(R, 3) = ファイル.Path R = R + 1 Next End Sub
実行結果
解説
今回のコードで最も重要なのが、For Eachの内部にあるこの部分です。
' ファイルの情報をシートに書き出す 出力シート.Cells(R, 1) = ファイル.Name 出力シート.Cells(R, 2) = ファイル.DateLastModified 出力シート.Cells(R, 3) = ファイル.Path
「Range.Value」や「Range.Formula」の様に、
ファイル.○○でファイルの各情報を取得できているのがわかります。
しかもこの○○は、Rangeと同じように以下の選択肢から入力ができます。
このファイルという変数は「Fileオブジェクト」と呼ばれる型の変数で、
Dim ファイル As File
このコードで宣言していた変数です。
- Range変数にセルをSetすれば「セル.○○」で情報を取得できる
- File変数にファイルをSetすれば「ファイル.○○」で情報を取得できる
こんな対応をさせるとわかりやすいでしょうか。
実はこれこそが今回のコードの、ひいてはFileSystemObjectの目的です。
ファイルを「Fileオブジェクト」の変数にSetすることで、
Fileオブジェクト.○○という形でいろいろな情報が取得できます。
「ファイルをRangeみたいに扱えるようになる」と思ってください。
この「ファイルをオブジェクトとして扱える」というのがFSO最大の特長です。
FSOはこのためにあるといっても過言ではありませんので、
まずはこれをしっかり覚えて次に進んでください。
さてその上で、ファイルをForEachでループしているこの部分を見てみましょう。
Dim ファイル As File For Each ファイル In 指定フォルダ.Files Next
この「指定フォルダ」という変数は「Folderオブジェクト」と呼ばれる型の変数で、
Fileオブジェクトと全く同じ説明ができるオブジェクトです。
つまり
- Folder変数にフォルダをSetすれば「フォルダ.○○」で情報を取得できる
こんなオブジェクトです。
そして重要なのが、この「Folder変数.○○」で取得できる情報の中に、
フォルダ内の全ファイルを取得する「Files」というプロパティがあるという点です。
FolderオブジェクトとFileオブジェクトは、
実際のフォルダとファイルの関係の様に親子関係が定義されているんですね。
この親子関係は、ファイルをRangeに例えたように、
フォルダをWorksheetに例えてみるとわかりやすいです。
「シート内のすべてのセルを処理する」コードと見比べてみてください。
Dim セル As Range For Each セル In シート.Cells Next
Dim ファイル As File For Each ファイル In 指定フォルダ.Files Next
まったく同じ構造のコードですよね。
Rangeに限らずこの手の「For Each 子 In 親.子s」というコードは、
(VBAの)万国共通こんな書き方をします。
つまり「教本通りの親子ForEach文が使える」というのもFSOの特長ですし、
裏を返せば「FSOの経験は他のオブジェクトにも活きる」とも言えます。
これが今回のコードの要旨ですので、まずはこれをしっかり叩き込んでください。
FSOとは「ファイルとフォルダをオブジェクトとして扱うための機能」です。
これさえ理解してしまえば、もうFSOのコードは何でも読めます。
あとはおまけみたいな話ですが、まだ解説が残っているのが
Dim 指定フォルダ As Folder Set 指定フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\テスト")
このコードですね。
これは
Dim シート As Worksheet Set シート = Worksheets("ファイル一覧")
このコードと同じようなものと思ってください。
何もないところにいきなりオブジェクトがあるわけではないので、
最初は文字列や数値からオブジェクトを取得する必要があるということです。
以上がFSOでファイル一覧を取得するコードの解説です。
ソースコードを再掲しますので眺めてみてください。
Public FSO As New FileSystemObject Sub 指定フォルダのファイル一覧をシートに書き出す() ' 出力するシートを取得 Dim 出力シート As Worksheet Set 出力シート = Worksheets("ファイル一覧") Dim R As Long: R = 2 ' GetFolderメソッドでFolderオブジェクトを取得する Dim 指定フォルダ As Folder Set 指定フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\テスト") ' Filesプロパティの中をForEachで順次取得する Dim ファイル As File For Each ファイル In 指定フォルダ.Files ' ファイルの情報をシートに書き出す 出力シート.Cells(R, 1) = ファイル.Name 出力シート.Cells(R, 2) = ファイル.DateLastModified 出力シート.Cells(R, 3) = ファイル.Path R = R + 1 Next End Sub
だいぶ読みやすくなったのではないでしょうか。
要旨をまとめると、
- Fileオブジェクト.○○で様々なファイル処理ができる
- Folderオブジェクト.○○で様々なフォルダ処理ができる
- 両者には親子関係があり、フォルダ内のファイルを「.Files」で取得できる
- このFilesはコレクションなので、ForEachでループ処理することができる
このような感じになります。
さらにこれを一言でまとめると、
「FileSystemObjectはファイル/フォルダをオブジェクトとして扱えるのが特長」
ということになります。
これされ理解してしまえばFSOのプロパティ/メソッド名は素直な英語なので、
読めたも同然ですし、なんなら勘で書いても割と動かせるようになります。
まずはこの特長をしっかり押さえておいてください。
フォルダ内の各ファイルを操作する
ファイルの一覧を取得したら、次はファイルに何か処理をしてみましょう。
先ほどFileオブジェクトをRangeオブジェクトに例えました。
Rangeオブジェクトには「Value」や「Formula」などの情報の他に、
「Copy」や「Delete」などの処理を実行できる機能があります。
このような機能はFileオブジェクトにも同様に備わっており、
ファイル.Copyやファイル.Moveなどでファイルを処理することが可能です。
例えば「しばらく更新されていないファイルを移動」してみましょう。
' ファイルの更新が30日前なら名前に【旧】を付けてバックアップに移動する Dim ファイル As File For Each ファイル In 指定フォルダ.Files If Day(Date - ファイル.DateLastModified) >= 30 Then ファイル.Name = "【旧】" & ファイル.Name ファイル.Move ThisWorkbook.Path & "\バックアップ\" End If Next
とても読みやすいコードになりましたね。
- ファイル.Name = ○○ という代入
- ファイル.Move ○○ という処理の実行
は、RangeやWorksheetでも見慣れた書き方だと思います。
このように、Dir系列ではステートメントとしてしか実行できなかった処理が、
FSOではプロパティの代入やメソッドの実行で表現できるようになります。
慣れると処理をサクサク書けるようになりますので、
セルやシートを扱うつもりでコードをいじってみてください。
フォルダ内のExcelファイルを処理する
最後にExcelファイルを開いて処理する場合のサンプルも置いておきます。
Public FSO As New FileSystemObject Sub 指定フォルダ内のExcelファイルに同じ処理を実行する() ' GetFolderメソッドでFolderオブジェクトを取得する Dim 指定フォルダ As Folder Set 指定フォルダ = FSO.GetFolder("C:\Users\○○\Desktop\テスト") ' フォルダ内のすべてのファイルをループ Dim ファイル As File For Each ファイル In 指定フォルダ.Files ' 拡張子がxlsxか判定 If FSO.GetExtensionName(ファイル.Path) = "xlsx" Then ' ブックを開く ⇒ 処理 ⇒ 保存 ⇒ 閉じる Workbooks.Open ファイル.Path Call ブックごとの処理(Workbooks(ファイル.Name)) Workbooks(ファイル.Name).Close SaveChanges:=True End If Next End Sub ' ブックごとの処理部分 Sub ブックごとの処理(wb As Workbook) Dim ws As Worksheet Set ws = wb.Worksheets(1) ws.Range("A1") = 1 End Sub
かなり読みやすいコードではないでしょうか。
重要なのはファイル操作とExcel操作を別のSubに分けている点です。
この2つのSubプロシージャを分けたことで、
- 第1Subの中ではファイル操作に集中できる
- 第2Subの中ではExcelの作業に集中できる
という恩恵があります。
ブックへの処理が第1Subの中ではCall1行になったことで、
ForEachブロックが見渡せるようになりましたからね。
Dim ファイル As File For Each ファイル In 指定フォルダ.Files If FSO.GetExtensionName(ファイル.Path) = "xlsx" Then Workbooks.Open ファイル.Path Call ブックごとの処理(Workbooks(ファイル.Name)) Workbooks(ファイル.Name).Close SaveChanges:=True End If Next
すべてのファイルに対して行われている
- 開く
- 処理する
- 保存して閉じる
という流れが、非常にわかりやすくなっていると思います。
そして第2Subでも、「ブックの処理だけを単独実行できる」という恩恵があります。
イミディエイトウィンドウで以下のコードを実行すれば、
手動で開いた好きなブックの検証ができるということです。
Call ブックごとの処理(ActiveWorkbook)
もしこのマクロを1つのSub内に全部書いてしまっていたら、
怪しいファイルがあってもそこにたどり着くまで待つ羽目になりますからね。
このように、プロシージャ分割をうまく使ってマクロを構造化すると、
処理の流れが掴みやすく、読みやすいコードになります。
特に「FSOによるファイル・フォルダ操作」「Excelによるワークシート処理」は、
分割も簡単で効果も高いので、積極的に使っていきましょう。
以上でFSOによるファイル一覧の取得方法の解説を終わります。
最も重要なポイントは、
「FileSystemObjectはファイル・フォルダをオブジェクトとして扱うための機能」
ということでしたね。
今回のコードさえ理解できてしまえば、もうFSOのコードは大体読めると思います。
これをしっかり抑えた上で、他のFSOメソッドも学習していってください。
◇ FileSystemObject入門シリーズ
【1】FileSystemObjectとは - Dir関数群との違い
【2】参照設定と変数宣言
【3】ファイル一覧の取得(本記事)
【4】すべての下層フォルダの取得
【5】FileSystemObjectって何が便利なの?