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 を使う方法(推奨)

参照設定なしで使用できるため、他の環境でも動作する汎用性の高い方法です。

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 行ずつ)

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 ファイルの読み込み

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 ファイルを一括処理

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 でファイルやフォルダを操作するための強力で柔軟なツールです。主な利点をまとめると:

  1. 統一されたインターフェース: ファイルとフォルダの操作を一貫した方法で実行できる
  2. 豊富な機能: 従来の VBA 関数では難しかった操作も簡単に実現できる
  3. オブジェクト指向: ファイルやフォルダをオブジェクトとして扱える
  4. エラー処理: 詳細なエラー情報を取得できる

従来の Dir 関数や Kill ステートメントと比較して、FileSystemObject は学習コストに見合うだけの価値がある機能です。特に複雑なファイル操作やフォルダ走査を行う場合に威力を発揮します。

ぜひ実際のプロジェクトで FileSystemObject を活用して、より効率的で保守性の高いコードを書いてみてください。

#VBA #FileSystemObject #ファイル操作 #フォルダ操作