和風スパゲティのレシピ

日本語でコーディングするExcelVBA

FileSystemObjectの呼び出しを短縮する方法

たとえばFileSystemObjectを使うサンプルコードとして、

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

' ファイルをコピー
FSO.CopyFile wbコピー元ブック.FullName _
                  , Pathコピー先フォルダ & "\" & wbコピー元ブック.Name

こんなコードを書くとします。

FileSystemObjectはとても便利なのですが、
この上の2行が面倒なんですよね。


慣れないうちはいちいちググってコピーしたり、
前に使った場所を探しに行ったりしてしまいます。


それを解決するのがこちらです↓

' Create部分を汎用関数として持っておく
Function FSO() As Object
    Static FSO_ As Object
    If FSO_ Is Nothing Then Set FSO_ = CreateObject("Scripting.FileSystemObject")
    Set FSO = FSO_
End Function

' 例:メインコード内では、いきなり「FSO」と呼ぶことができる
Sub サンプルマクロ

    ' ファイルをコピー
    FSO.CopyFile wbコピー元ブック.FullName _
                      , Pathコピー先フォルダ & "\" & wbコピー元ブック.Name

End Sub

面倒なCreateObject部分を関数にやらせておくことで、
メインコードではその関数を呼び出すだけ
でよくなっていますね。


このように、常に同じオブジェクトを使うようなコードは、
そのオブジェクトを返す関数を作ってしまうと便利です。

こうすることで、そのオブジェクトをあたかも定数のように扱えます。


他の簡単な例として、

' 汎用関数
Function Fx() As WorksheetFunction
    Set Fx = WorksheetFunction
End Function

' 使用例
Fx.Sum(合計したいセル範囲)

などもおすすめです。

コードの解説

Function FSO() As Object
    Static FSO_ As Object
    If FSO_ Is Nothing Then Set FSO_ = CreateObject("Scripting.FileSystemObject")
    Set FSO = FSO_
End Function

FileSystemObjectは何個も作るのはちょっと好ましくなさそうなので、
Static変数に入れて、初回呼び出し時のみCreateしています。

 

'' ※ 一応これでも同じ動きをしてくれるが、呼び出すたびに新しくCreateObjectされてしまう。
Function FSO() As Object
    Set FSO = CreateObject("Scripting.FileSystemObject")
End Function

※ FileSystemObjectは、「プロジェクト全体で生成インスタンスが1個だけ」になるよう制御されているとのことで、厳密には何個もFileSystemObjectを作れるわけではありません。ただしStatic変数に入れると実行速度が早くなるところを見ると、CreateObjectのたびに何らかの処理が入っているため、CreateObjectの回数を減らす意味はあるようです。


また、このままでは「FSO.」と打った時に入力候補(メンバー表示)がでません
(関数の返り値がObject型のため)


「Microsoft Scripting Runtime」を参照設定した上で、

Function FSO() As FileSystemObject
    Static FSO_ As Object
    If FSO_ Is Nothing Then Set FSO_ = CreateObject("Scripting.FileSystemObject")
    Set FSO = FSO_
End Function

このように「関数の返り値の型をFileSystemObjectにする」ことで、


FileSystemObjectのメンバー

と、メンバーを表示させることができます。


が、今回作った関数は「汎用関数」ですからね。

「汎用関数集をモジュールごとコピーして使う」ような運用もしたいわけで、
この時、FSOを使わないブックでもいちいち参照設定したくありません。


その解決策としては、

' Function FSO() As FileSystemObject ' コーディング用
Function FSO() As Object ' 配付用
    Static FSO_ As Object
    If FSO_ Is Nothing Then Set FSO_ = CreateObject("Scripting.FileSystemObject")
    Set FSO = FSO_
End Function

と、Functionの宣言部を2通り書いておき、メンバー候補を使いたいときは参照設定後にコメントアウトを切り替えるという方法があります。

こうすれば、参照設定をしていなくてもコンパイルエラーは発生しませんし、
メンバー候補がいらない程度のコードを書くときはこのままでも動きます。

必ず参照設定をする場合

上記の関数化の方法は、「汎用関数」として、
Microsoft Scripting Runtimeの参照の有無にかかわらず使える
ことを目的にしています。


しかし、開き直って「全部のファイルで参照設定しちゃう」という前提であれば、

 

Dim FSO As New Scripting.FileSystemObject

' ファイルをコピー
FSO.CopyFile wbコピー元ブック.FullName _
                  , Pathコピー先フォルダ & "\" & wbコピー元ブック.Name

この参照設定バージョンの宣言部1行をプロシージャの外に出し、

 

Public FSO As New Scripting.FileSystemObject

Sub サンプルマクロ
    ' ファイルをコピー
    FSO.CopyFile wbコピー元ブック.FullName _
                      , Pathコピー先フォルダ & "\" & wbコピー元ブック.Name
End Sub

Public変数としてNewまで済ませてしまうこともできます。

「汎用関数」ならぬ、「汎用変数」ですね。


この方法を採用した場合、この変数を宣言したモジュールを使うブックでは、
必ずMicrosoft Scripting Runtimeの参照が必要になります。

汎用関数モジュールの作り方に制限が出たり、使い勝手が多少落ちるため、私は関数バージョンを使っています。
しかしそれはそれで、上記の通りメンバー表示を出すのが面倒という弱点もあります。


Microsoft Scripting Runtimeは「Dictionary」にも使いますので、
これと合わせて、どんどん参照設定していくのも便利だと思います。

「開き直って全部のファイルを参照設定してしまう」=「新規ブックのテンプレートに参照設定をつけてしまう」
なんて技も有用らしいので、好みで使い分けてください。

おまけ:ユーザー辞書を使おう

dmfそ Dim FSO As Object
dmfそ2 Set FSO = CreateObject("Scripting.FileSystemObject")

とユーザー辞書(変換)に登録しておけば、
汎用関数が無い環境でも割と簡単にFSOを呼び出すことができます。


dmをなくして、「fそ」だけの変換にすると、
実際にFSO変数を使うときにも誤変換されちゃうので注意してください。

宣言系は全部dmから始めるとかにしておくと、忘れにくくていいと思います。


なお、マルチステートメント「:」をつかって、

dmfそ Dim FSO As Object :Set FSO = CreateObject("Scripting.FileSystemObject")

の一発変換ができる人はこっちがいいと思いますが、
たぶん字数制限に引っかかると思います。