File As Object 深い階層からファイルを上の階層に引きあげる

【VBA FSO】FileSystemObjectで一番したいことは何?深い階層のフォルダからファイルを救出。

動画編深い階層のフォルダからファイルを救出。
タイトル

【VBA FSO】FileSystemObjectで一番したいことは何?深い階層のフォルダからファイルを救出。

深い階層のフォルダからファイルを上の階層に上げたい

動画版「FSOの使い方」です。FileSystemObject(ファイルシステムオブジェクト)はファイルとフォルダ操作をするために用意されたオブジェクトです。オブジェクトというとそれだけで敬遠されがちです。 しかし、そこを乗り越えるととても便利で快適なExcel環境、いやPC環境が手に入ります。

マクロ動画 タイトル

https://youtu.be/6BWDFHj9t4k

親フォルダ、子フォルダ、ファイル

今回することは 親フォルダー、子フォルダー、その中にファイル という構成から 親フォルダー 直下にファイルを上げてやる という 操作です。
以下の図はそのためにあえて分割したフォルダとfile群です。

NAMAE1

マクロを実行すると、子フォルダーから親フォルダにファイルが移動します。 その時に 所属が不明にならないように、 ファイルが所属していた 子フォルダーの名前をファイル名の前につけるようにしています。

NAMAE2

また、空になった子フォルダは削除するようにしました。 これにより目的のファイルへのアクセスが素早くできるようになりました。

NAMAE3

fileを上の階層にあげるマクロコード

では、どのようなコードを書いたのが説明します。
今回のコード作成にあたり、FileSystemObjectを使っています。
FileSystemObject(ファイルシステムオブジェク卜、略してFSO)は、ドライブやフォルダ一、ファイルを 操作するためのオブジェク卜です。
FSOを使用すると、ファイルやフォルダーを処理するプログラムを「オブジェクト.メソッド」や 「オブジェクト.プロパティ」といったVBAの基本構文で記述することができます。

NAMAE6

FileSystemObjectは、下図のようなコレクションとオブジェクトにより構成されています。
最上位のオブジェクトは FileSystemObjectオブジェクトです。そのほかのオブジェクトは、 すぺてFileSystemObjectの下位オブジェクトになります。

NAMAE7

FileSystemObjectを使うには、[MicroSoft Scripting Runtime] への参照設定を行う必要があります。 VBEを開きから以下のステップで参照設定を行います。:
1.メニューのツールをクリックします。
2.ツールの参照設定をクリックします。
3.表示される参照可能なライブラリから、「Microsoft Scripting Runtime」を探し、
4.「Microsoft Scripting Runtime」の左にあるチェック欄にチェックを入れます。OKをクリックして閉じます。
以上で FileSystemObjectを利用できるようになります。(事前バインディング)

NAMAE8

参照設定ができない時(実行時バインディング)

下図にあるように、「Microsoft Scripting Runtime」が利用できない時には、 CreateObjectメソッドを使ってFileSystemObjectを使うためのObjectを作成(インスタンス化)します。

Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")

NAMAE9

両方できるからと言って、どちらでも良いと考えるよりは、 基本的には、参照設定を使うと考えてください。
では変数を見ていきましょう。

NAMAE10

使う変数について

親フォルダは、 Dim ParentFolder As Object,
子フォルダ、 ChildFolder As Object,
ファイル、File As Object
選択したフォルダへのパス、Dim sParentFolderPath As String
として使っています。そして、
Dim fso As New FileSystemObject
変数fsoをFileSystemObjectのobjectとして宣言し、インスタンス化しています。

NAMAE17

以下のWith構文では、ユーザーに使用するフォルダを選択してもらうためのコードを記述しています。 このコードを入れない場合は、直接フォルダへのパスを指定する必要があります。
コードは短くなりますが、処理を行うたびにフォルダへのパスを確認したり、書き換えたりする手間が発生するので、 汎用性を考えると、With構文で、ユーザーに使用するフォルダを選択してもらう方が簡単です。

NAMAE11
   ' 親フォルダの選択
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "親フォルダ(例:TOEIC単語)を選択してください"
        If .Show = -1 Then
            sParentFolderPath = .SelectedItems(1)
        Else
            Exit Sub
        End If
    End With

親フォルダが決まったので、次は子フォルダをFor Each構文を使って、 ParentFolder.SubFoldersというように、親フォルダに属する サブフォルダーコレクションの中から、それぞれ一つずつ処理します。

NAMAE12
    ' 親フォルダ内の子フォルダを取得
    Set ParentFolder = fso.GetFolder(sParentFolderPath)
    For Each ChildFolder In ParentFolder.SubFolders
        ' 子フォルダ内の各ファイルを取得
        For Each File In ChildFolder.Files
            If Right(File.Name, 4) = ".mp3" Then
                ' ファイルを親フォルダに移動
                File.Move sParentFolderPath & "\" & _
                    ChildFolder.Name & "_" & File.Name
            End If
        Next File

    Next ChildFolder

さらにその子フォルダの中にあるファイルを処理するので、 For文を入れ子で使います。

NAMAE13

赤線を引いたコードが今回のマクロのコードの大事な部分です。
今回の処理したい対象ファイルだったら、Moveメソッドを使い
以下の名前をつけて移動しなさい。という内容の処理です。

NAMAE14

最後に、子フォルダに対象ファイルしか存在しない場合、空のフォルダになってしまいますから、 そのフォルダは不要です。そこでフォルダ内に他のファイルやフォルダが存在しない場合にはDeleteメソッドを使って削除しています。

NAMAE15

今回のコード全体は以下になります。

Sub ファイルを上の階層フォルダーへ移動()
    Dim ParentFolder As Object, ChildFolder As Object
    Dim File As Object
    Dim sParentFolderPath As String

'    FileSystemObjectを初期化
'    Dim fso As Object,
'    Set fso = CreateObject("Scripting.FileSystemObject")
    Dim fso As New FileSystemObject
    ' 親フォルダの選択
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = "親フォルダ(例:TOEIC単語)を選択してください"
        If .Show = -1 Then
            sParentFolderPath = .SelectedItems(1)
        Else
            Exit Sub
        End If
    End With

    ' 親フォルダ内の子フォルダを取得
    Set ParentFolder = fso.GetFolder(sParentFolderPath)
    For Each ChildFolder In ParentFolder.SubFolders
        ' 子フォルダ内の各ファイルを取得
        For Each File In ChildFolder.Files
            If Right(File.Name, 4) = ".mp3" Then
                ' ファイルを親フォルダに移動
                File.Move sParentFolderPath & "\" & _
                    ChildFolder.Name & "_" & File.Name
            End If
        Next File

    Next ChildFolder
 ' 空のフォルダを削除する処理を追加
    Set ParentFolder = fso.GetFolder(sParentFolderPath)
    For Each ChildFolder In ParentFolder.SubFolders
        If ChildFolder.Files.Count = 0 And _
            ChildFolder.SubFolders.Count = 0 Then
            ChildFolder.Delete
        End If
    Next ChildFolder
    MsgBox "完了しました。", vbInformation
End Sub
NAMAE5