FileSystemObject
VBA でファイルやフォルダを操作する方法として、従来の Dir
関数や Kill
ステートメントなどがありますが、より強力で柔軟な操作を実現できるのが FileSystemObject (FSO) です。
この記事では、FileSystemObject の基本的な使い方から実践的な活用例まで、初心者にもわかりやすく解説します。
FileSystemObject とは
FileSystemObject は、Windows のファイルシステムにアクセスするためのオブジェクトです。Microsoft Scripting Runtime ライブラリの一部として提供されており、ファイルやフォルダの作成、削除、コピー、移動、読み書きなど、様々な操作を統一的なインターフェースで実行できます。
FileSystemObject の特徴
- オブジェクト指向: ファイルやフォルダをオブジェクトとして扱える
- 豊富な機能: ファイル・フォルダの操作がほぼすべて可能
- テキストファイル処理: テキストファイルの読み書きが簡単
- エラー処理: 詳細なエラー情報を取得できる
- クロスプラットフォーム: Windows Script Host と共通のオブジェクトモデル
従来の VBA 関数との比較
操作 | 従来の方法 | FileSystemObject |
---|---|---|
ファイル存在確認 | Dir 関数 | FileExists メソッド |
ファイル削除 | Kill ステートメント | DeleteFile メソッド |
フォルダ作成 | MkDir ステートメント | CreateFolder メソッド |
テキスト読込 | Line Input # | ReadLine メソッド |
ファイル属性取得 | GetAttr 関数 | File.Attributes プロパティ |
FileSystemObjectを使用するには、「Microsoft Scripting
Runtime」への参照設定が推奨されますが、CreateObject("Scripting.FileSystemObject")
を使用すれば参照設定なしでも利用できます。
FileSystemObject の基本的な使い方
インスタンスの作成
FileSystemObject を使用するには、まずインスタンスを作成する必要があります。
参照設定を使う方法
VBA エディタで「ツール」→「参照設定」から「Microsoft Scripting Runtime」にチェックを入れます。
Dim fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
' 処理...
' 後始末
Set fso = Nothing
CreateObject を使う方法(推奨)
参照設定なしで使用できるため、他の環境でも動作する汎用性の高い方法です。
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
' 処理...
' 後始末
Set fso = Nothing
CreateObject
を使う方法は、参照設定が不要で他の環境でも動作するため、特別な理由がない限りこちらを使用することをお勧めします。
ファイル操作
ファイルの存在確認
Sub CheckFileExists()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\sample.txt"
If fso.FileExists(filePath) Then
MsgBox "ファイルが存在します"
Else
MsgBox "ファイルが存在しません"
End If
Set fso = Nothing
End Sub
ファイルのコピー
Sub CopyFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim sourceFile As String
Dim destFile As String
sourceFile = "C:\Temp\original.xlsx"
destFile = "C:\Backup\copy.xlsx"
' ファイルをコピー(第2引数Trueで上書き許可)
fso.CopyFile sourceFile, destFile, True
MsgBox "ファイルをコピーしました"
Set fso = Nothing
End Sub
ファイルの移動
Sub MoveFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim sourceFile As String
Dim destFile As String
sourceFile = "C:\Temp\file.txt"
destFile = "C:\Archive\file.txt"
' ファイルを移動
fso.MoveFile sourceFile, destFile
MsgBox "ファイルを移動しました"
Set fso = Nothing
End Sub
ファイルの削除
Sub DeleteFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\delete_me.txt"
If fso.FileExists(filePath) Then
' ファイルを削除(第2引数Trueで強制削除)
fso.DeleteFile filePath, True
MsgBox "ファイルを削除しました"
Else
MsgBox "ファイルが存在しません"
End If
Set fso = Nothing
End Sub
DeleteFile
メソッドでファイルを削除すると、ゴミ箱には移動されず、完全に削除されます。実行前に必ず確認処理を入れることをお勧めします。
ファイル情報の取得
Sub GetFileInfo()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\sample.xlsx"
If fso.FileExists(filePath) Then
Dim file As Object
Set file = fso.GetFile(filePath)
Debug.Print "ファイル名: " & file.Name
Debug.Print "フルパス: " & file.Path
Debug.Print "サイズ: " & file.Size & " バイト"
Debug.Print "作成日時: " & file.DateCreated
Debug.Print "更新日時: " & file.DateLastModified
Debug.Print "アクセス日時: " & file.DateLastAccessed
Debug.Print "親フォルダ: " & file.ParentFolder
Set file = Nothing
End If
Set fso = Nothing
End Sub
ファイル名の変更
Sub RenameFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\old_name.txt"
If fso.FileExists(filePath) Then
Dim file As Object
Set file = fso.GetFile(filePath)
' ファイル名を変更
file.Name = "new_name.txt"
MsgBox "ファイル名を変更しました"
Set file = Nothing
End If
Set fso = Nothing
End Sub
フォルダ操作
フォルダの存在確認
Sub CheckFolderExists()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp\MyFolder"
If fso.FolderExists(folderPath) Then
MsgBox "フォルダが存在します"
Else
MsgBox "フォルダが存在しません"
End If
Set fso = Nothing
End Sub
フォルダの作成
Sub CreateFolder()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp\NewFolder"
If Not fso.FolderExists(folderPath) Then
fso.CreateFolder folderPath
MsgBox "フォルダを作成しました"
Else
MsgBox "フォルダは既に存在します"
End If
Set fso = Nothing
End Sub
サブフォルダを含むフォルダの作成
Sub CreateFolderRecursive()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp\Parent\Child\GrandChild"
' 親フォルダが存在しなくても自動的に作成される
If Not fso.FolderExists(folderPath) Then
fso.CreateFolder folderPath
MsgBox "フォルダを作成しました"
End If
Set fso = Nothing
End Sub
フォルダのコピー
Sub CopyFolder()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim sourceFolder As String
Dim destFolder As String
sourceFolder = "C:\Temp\SourceFolder"
destFolder = "C:\Backup\DestFolder"
' フォルダをコピー(第2引数Trueで上書き許可)
fso.CopyFolder sourceFolder, destFolder, True
MsgBox "フォルダをコピーしました"
Set fso = Nothing
End Sub
フォルダの削除
Sub DeleteFolder()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp\OldFolder"
If fso.FolderExists(folderPath) Then
' フォルダを削除(第2引数Trueで強制削除)
fso.DeleteFolder folderPath, True
MsgBox "フォルダを削除しました"
Else
MsgBox "フォルダが存在しません"
End If
Set fso = Nothing
End Sub
DeleteFolder
メソッドは、フォルダ内のすべてのファイルとサブフォルダも含めて削除します。削除前に必ずバックアップを取るか、ユーザーに確認を求めることを強くお勧めします。
フォルダ内のファイル一覧を取得
Sub ListFiles()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp"
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
Dim file As Object
For Each file In folder.Files
Debug.Print file.Name & " - " & file.Size & " バイト"
Next file
Set folder = Nothing
End If
Set fso = Nothing
End Sub
サブフォルダ一覧を取得
Sub ListSubFolders()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp"
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
Dim subFolder As Object
For Each subFolder In folder.SubFolders
Debug.Print subFolder.Name & " - " & subFolder.Path
Next subFolder
Set folder = Nothing
End If
Set fso = Nothing
End Sub
テキストファイルの操作
テキストファイルの読み込み(全行)
Sub ReadTextFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\sample.txt"
If fso.FileExists(filePath) Then
Dim textStream As Object
Set textStream = fso.OpenTextFile(filePath, 1) ' 1=読み取りモード
' ファイル全体を読み込み
Dim content As String
content = textStream.ReadAll
Debug.Print content
textStream.Close
Set textStream = Nothing
End If
Set fso = Nothing
End Sub
テキストファイルの読み込み(1 行ずつ)
Sub ReadTextFileLineByLine()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\sample.txt"
If fso.FileExists(filePath) Then
Dim textStream As Object
Set textStream = fso.OpenTextFile(filePath, 1)
' ファイルの終わりまで1行ずつ読み込み
Do Until textStream.AtEndOfStream
Dim line As String
line = textStream.ReadLine
Debug.Print line
Loop
textStream.Close
Set textStream = Nothing
End If
Set fso = Nothing
End Sub
テキストファイルへの書き込み(上書き)
Sub WriteTextFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\output.txt"
' 2=書き込みモード, True=新規作成またはコ書き
Dim textStream As Object
Set textStream = fso.CreateTextFile(filePath, True)
' テキストを書き込み
textStream.WriteLine "1行目のテキスト"
textStream.WriteLine "2行目のテキスト"
textStream.WriteLine "3行目のテキスト"
textStream.Close
Set textStream = Nothing
MsgBox "ファイルに書き込みました"
Set fso = Nothing
End Sub
テキストファイルへの追記
Sub AppendToTextFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\log.txt"
Dim textStream As Object
Set textStream = fso.OpenTextFile(filePath, 8, True) ' 8=追記モード, True=ファイルがなければ作成
' ログエントリを追記
textStream.WriteLine Now & " - 処理を開始しました"
textStream.WriteLine Now & " - データを処理しました"
textStream.WriteLine Now & " - 処理が完了しました"
textStream.Close
Set textStream = Nothing
Set fso = Nothing
End Sub
CSV ファイルの読み込み
Sub ReadCSVFile()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\data.csv"
If fso.FileExists(filePath) Then
Dim textStream As Object
Set textStream = fso.OpenTextFile(filePath, 1)
' ヘッダー行をスキップ
If Not textStream.AtEndOfStream Then
textStream.ReadLine
End If
' データ行を処理
Do Until textStream.AtEndOfStream
Dim line As String
line = textStream.ReadLine
' カンマで分割
Dim fields() As String
fields = Split(line, ",")
' データを処理
Debug.Print "列1: " & fields(0) & ", 列2: " & fields(1)
Loop
textStream.Close
Set textStream = Nothing
End If
Set fso = Nothing
End Sub
実践的な活用例
例 1: フォルダ内の Excel ファイルを一括処理
Sub ProcessAllExcelFiles()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Temp\ExcelFiles"
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
Dim file As Object
For Each file In folder.Files
' Excelファイルのみ処理
If LCase(fso.GetExtensionName(file.Name)) = "xlsx" Or _
LCase(fso.GetExtensionName(file.Name)) = "xlsm" Then
Debug.Print "処理中: " & file.Name
' ここにExcelファイルの処理を記述
' ProcessExcelFile file.Path
End If
Next file
Set folder = Nothing
End If
Set fso = Nothing
MsgBox "すべてのファイルを処理しました"
End Sub
例 2: 古いバックアップファイルを自動削除
Sub DeleteOldBackups()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim folderPath As String
folderPath = "C:\Backup"
' 30日より古いファイルを削除
Dim cutoffDate As Date
cutoffDate = DateAdd("d", -30, Date)
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
Dim file As Object
For Each file In folder.Files
If file.DateLastModified < cutoffDate Then
Debug.Print "削除: " & file.Name & " (更新日: " & file.DateLastModified & ")"
file.Delete
End If
Next file
Set folder = Nothing
End If
Set fso = Nothing
MsgBox "古いバックアップファイルを削除しました"
End Sub
例 3: フォルダ構造を再帰的に走査
Sub ScanFoldersRecursive(folderPath As String, Optional level As Long = 0)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
' インデントを作成
Dim indent As String
indent = String(level * 2, " ")
Debug.Print indent & "[フォルダ] " & folder.Name
' サブフォルダを再帰的に処理
Dim subFolder As Object
For Each subFolder In folder.SubFolders
ScanFoldersRecursive subFolder.Path, level + 1
Next subFolder
' ファイルを表示
Dim file As Object
For Each file In folder.Files
Debug.Print indent & " " & file.Name
Next file
Set folder = Nothing
End If
Set fso = Nothing
End Sub
' 使用例
Sub TestScan()
ScanFoldersRecursive "C:\Temp"
End Sub
例 4: ログファイルの作成
Sub CreateLog(message As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim logPath As String
logPath = ThisWorkbook.Path & "\log.txt"
Dim textStream As Object
Set textStream = fso.OpenTextFile(logPath, 8, True) ' 追記モード
' タイムスタンプ付きでログを記録
textStream.WriteLine Format(Now, "yyyy-mm-dd hh:nn:ss") & " - " & message
textStream.Close
Set textStream = Nothing
Set fso = Nothing
End Sub
' 使用例
Sub ProcessWithLogging()
CreateLog "処理を開始しました"
' 何らかの処理
On Error GoTo ErrorHandler
' 処理が成功
CreateLog "処理が正常に完了しました"
Exit Sub
ErrorHandler:
CreateLog "エラーが発生しました: " & Err.Description
End Sub
例 5: ファイルサイズの合計を計算
Function GetFolderSize(folderPath As String) As Double
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim totalSize As Double
totalSize = 0
If fso.FolderExists(folderPath) Then
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
' ファイルサイズの合計
Dim file As Object
For Each file In folder.Files
totalSize = totalSize + file.Size
Next file
' サブフォルダも再帰的に計算
Dim subFolder As Object
For Each subFolder In folder.SubFolders
totalSize = totalSize + GetFolderSize(subFolder.Path)
Next subFolder
Set folder = Nothing
End If
Set fso = Nothing
GetFolderSize = totalSize
End Function
' 使用例
Sub ShowFolderSize()
Dim folderPath As String
folderPath = "C:\Temp"
Dim sizeInBytes As Double
sizeInBytes = GetFolderSize(folderPath)
Dim sizeInMB As Double
sizeInMB = sizeInBytes / 1024 / 1024
MsgBox "フォルダサイズ: " & Format(sizeInMB, "#,##0.00") & " MB"
End Sub
パス操作の便利なメソッド
パスの結合
Sub BuildPath()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim basePath As String
basePath = "C:\Temp"
' パスを結合(自動的に\を追加)
Dim fullPath As String
fullPath = fso.BuildPath(basePath, "SubFolder\file.txt")
Debug.Print fullPath ' => C:\Temp\SubFolder\file.txt
Set fso = Nothing
End Sub
ファイル名の取得
Sub GetFileName()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim fullPath As String
fullPath = "C:\Temp\SubFolder\document.xlsx"
' ファイル名を取得
Dim fileName As String
fileName = fso.GetFileName(fullPath)
Debug.Print fileName ' => document.xlsx
' 基底名を取得(拡張子なし)
Dim baseName As String
baseName = fso.GetBaseName(fullPath)
Debug.Print baseName ' => document
' 拡張子を取得
Dim extension As String
extension = fso.GetExtensionName(fullPath)
Debug.Print extension ' => xlsx
Set fso = Nothing
End Sub
親フォルダのパスを取得
Sub GetParentFolder()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim fullPath As String
fullPath = "C:\Temp\SubFolder\file.txt"
' 親フォルダのパスを取得
Dim parentPath As String
parentPath = fso.GetParentFolderName(fullPath)
Debug.Print parentPath ' => C:\Temp\SubFolder
Set fso = Nothing
End Sub
エラー処理のベストプラクティス
Sub SafeFileOperation()
On Error GoTo ErrorHandler
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim filePath As String
filePath = "C:\Temp\important.xlsx"
' ファイル操作前に存在確認
If Not fso.FileExists(filePath) Then
MsgBox "ファイルが見つかりません: " & filePath
Exit Sub
End If
' ファイル操作
Dim file As Object
Set file = fso.GetFile(filePath)
' 読み取り専用属性をチェック
If file.Attributes And 1 Then
MsgBox "ファイルは読み取り専用です"
Exit Sub
End If
' 処理...
Set file = Nothing
Set fso = Nothing
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description & vbCrLf & _
"エラー番号: " & Err.Number
' クリーンアップ
If Not file Is Nothing Then Set file = Nothing
If Not fso Is Nothing Then Set fso = Nothing
End Sub
ファイル操作は、アクセス権限やファイルロックなどの理由で失敗する可能性が高いため、必ずエラー処理を実装してください。
よくある質問とトラブルシューティング
Q1: “パスが見つかりません”エラーが発生する
原因: 指定したパスが存在しないか、アクセス権限がない
解決策:
' パスの存在確認を必ず行う
If fso.FolderExists(folderPath) Then
' 処理
Else
MsgBox "フォルダが存在しません: " & folderPath
End If
Q2: テキストファイルの文字化けを防ぎたい
解決策:
' UTF-8で読み込み
Dim stream As Object
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' テキストモード
stream.Charset = "UTF-8"
stream.Open
stream.LoadFromFile filePath
Dim content As String
content = stream.ReadText
stream.Close
Set stream = Nothing
Q3: ファイルが使用中で削除できない
解決策:
Function IsFileOpen(filePath As String) As Boolean
On Error Resume Next
Dim fileNum As Integer
fileNum = FreeFile
Open filePath For Binary Access Read Lock Read As #fileNum
Close #fileNum
IsFileOpen = (Err.Number <> 0)
On Error GoTo 0
End Function
まとめ
FileSystemObject は、VBA でファイルやフォルダを操作するための強力で柔軟なツールです。主な利点をまとめると:
- 統一されたインターフェース: ファイルとフォルダの操作を一貫した方法で実行できる
- 豊富な機能: 従来の VBA 関数では難しかった操作も簡単に実現できる
- オブジェクト指向: ファイルやフォルダをオブジェクトとして扱える
- エラー処理: 詳細なエラー情報を取得できる
従来の Dir
関数や Kill
ステートメントと比較して、FileSystemObject は学習コストに見合うだけの価値がある機能です。特に複雑なファイル操作やフォルダ走査を行う場合に威力を発揮します。
ぜひ実際のプロジェクトで FileSystemObject を活用して、より効率的で保守性の高いコードを書いてみてください。