FileSystemObjectとは
FileSystemObjectとは、ファイルやフォルダやディスクドライブを操作するクラスです。
操作するための各種メソッド(関数)やプロパティ(値の取得や設定)が用意されています。それらのメソッドやプロパティについては「FileSystemObjectとTextStreamのメソッド・プロパティ一覧」をご参照ください。
FileSystemObjectクラスは基本的なファイルやフォルダ操作だけでなく、複数のファイルやフォルダをまとめて扱うことが出来たり、ファイルの存在チェックを行うことが出来たりと便利なメソッドやプロパティが用意されています。
ファイルの内容に対する読み書きなどの操作はTextStreamクラスの各種メソッドやプロパティを利用します。
一般的に、FileSystemObjectクラスを扱う場合はTextStreamクラスも一緒に扱うことが多いため、「FileSystemObject」と言う場合は厳密には間違っていますが暗にTextStreamクラスも含めていることがあります。
FileSysteObjectクラスとTextStreamクラスの関係性や使い方については後述します。
TextStreamとは
TextStreamとは、ファイルの読み書きなどのファイルの内容の操作を行うクラスで、ファイル操作の各種メソッドやプロパティが用意されています。
TextStreamクラスは単体では利用できません。
FileSystemObjectクラスのCreateTextFileメソッドもしくはOpenTextFileメソッドで操作対象のファイルを指定し、その戻り値としてTextStreamクラスのオブジェクト変数が返却されることで、TextStreamオブジェクトの利用が可能になります。
事前設定
FileSystemObjectクラスおよびTextStreamクラスを利用するには、事前にVBA画面→ツールメニュー→参照設定、を選択し、参照設定ダイアログで「Microsoft Scripting Runtime」にチェックを付けます。
「Microsoft Scripting Runtime」にチェックを付けなくてもCreateObject関数を使うとFileSystemObjectとTextStreamは利用できますが、ここでは参照設定済みとして話を進めます。
参照設定をした場合とCreateObject関数を使う場合ではコードの書き方が異なります。どれでもいいですが私は最初の1行で書く方法でよく書いてます。1行で書いてよいかどうかの詳細は「VBAでクラス変数の宣言とNewを1行で書いてよいか」をご参照ください。
参照設定時+Newを1行にするコードの書き方
Newを1行で書く場合は変数宣言と同時にFileSystemObjectの各メソッドが利用できるようになります。
1 2 3 |
Sub FileSystemObjectTest1() Dim fso As New FileSystemObject End Sub |
参照設定時+変数宣言とSetを別行に分けるコードの書き方
変数宣言とSetを分けて各場合は、SetでFileSystemObjectクラスのインスタンスが作成後にFileSystemObjectの各メソッドが利用できるようになります。
1 2 3 4 |
Sub FileSystemObjectTest2() Dim fso As FileSystemObject Set fso = New FileSystemObject End Sub |
CreateObject関数を使う場合のコードの書き方
CreateObject関数を使う場合は、CreateObjectでFileSystemObjectクラスのインスタンスが作成後にFileSystemObjectの各メソッドが利用できるようになります。
1 2 3 4 |
Sub FileSystemObjectTest3() Dim fso As Object Set fso = CreateObject("Scripting.FileSystemObject") End Sub |
FileSystemObjectとTextStreamの関連性
FileSystemObjectクラスとTextStreamクラスはそれぞれファイルを扱うことが出来ますが用途が異なります。
FileSystemObjectクラスは、ファイルの削除、ファイルの移動、ファイル名の取得、など、ファイルそのものの操作を行います。
TextStreamクラスは、ファイルに書かれているデータ内容の取得や読み書きなど、ファイルの内容に対する操作を行います。
FileSystemObjectクラスとTextStreamクラスは親子関係にあり、FileSystemObjectクラスのCreateTextFileメソッド(ファイル作成)やOpenTextFileメソッド(ファイルを開く)の戻り値としてTextStreamクラスオブジェクトが返され、それを利用することで、CreateTextFileメソッドやOpenTextFileメソッドの引数で指定したファイルに対して操作を行えるようになります。
一般的には以下のようなコードになります。
1 2 3 4 5 6 7 8 9 10 |
Sub FileSystemObjectTest1() Dim fso As New FileSystemObject Dim ts As TextStream Set ts = fso.OpenTextFile(Filename:="V:\test\a.txt") '// ファイル操作:中略 ts.Close End Sub |
ファイルの読み書きを行うサンプルコード
以下のコードは「Microsoft Scripting Runtime」への参照設定を行った場合のサンプルです。
FileSystemObjectクラスのFileExistsメソッドを使ってファイルの存在をチェックし、ファイルが存在していればファイルに対してFileSystemObjectクラスのOpenTextFileメソッドでファイルを開き、ファイルに書かれている内容を取得し、その後FileSystemObjectクラスのCreateTextFileメソッドでファイルの内容を書き換え、さらに追記を行っています。
コードは多少長いですがやってることは大したことはやっていませんので後述の説明も合わせて確認してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
Sub FileSystemObjectTest4() Dim fso As New FileSystemObject '// FileSystemObject Dim ts As TextStream '// TextStream Dim sFilePath As String '// ファイルパス Dim sLine As String '// ファイル行 '// ファイルパスを指定 sFilePath = "V:\test\a.txt" '// ファイルが存在しない場合 If (fso.FileExists(sFilePath) = False) Then '// 関数を抜ける Exit Sub End If '// 以降、ファイルが存在する場合 '// ファイルを開く Set ts = fso.OpenTextFile(FileName:=sFilePath, IOMode:=ForReading) Do '// ファイルの終端の場合 If (ts.AtEndOfStream = True) Then '// ループを抜ける Exit Do End If '// 1行読み込み sLine = ts.ReadLine Debug.Print sLine Loop '// ファイルを閉じる ts.Close '// ファイルを新規書き込み用(上書き)で開く Set ts = fso.CreateTextFile(FileName:=sFilePath, Overwrite:=True) '// ファイルへ改行文字を含み書き込み Call ts.WriteLine("abc") Call ts.WriteLine("def") '// ファイルを閉じる ts.Close '// ファイルを追記書き込み用(追記)で開く Set ts = fso.OpenTextFile(FileName:=sFilePath, IOMode:=ForAppending) '// ファイルへ改行文字を含み書き込み Call ts.WriteLine("123") Call ts.WriteLine("456") '// ファイルを閉じる ts.Close End Sub |
サンプルコードは大きく分けると4つの処理に分かれています。
ファイル存在チェック、ファイルを読み込み、ファイルを上書き、ファイルへ追記、の4つです。
10行目のファイル存在チェックはFileSystemObjectのFileExistsメソッドを利用して、ファイルが存在しない(False)の場合は以降の処理を行わないように関数を抜けています。
19行目のファイルの読み込みはOpenTextFileメソッドの引数IOMode:=ForReadingを設定します。ファイルの終端をTextStreamクラスのAtEndOfStreamプロパティで判定し、終端でなければReadLineメソッドでファイルの行をファイルの上から順に取得します。
37行目のファイルの上書きはCreateTextFileメソッドの引数Overwrite:=Trueを設定します。WriteLineメソッドを使ってファイルに書き込みますが、上書きモードで開いているため既存のファイルの内容は消去された上で書き込みが行われます。
47行目のファイルの追記はOpenTextFileメソッドの引数IOMode:=ForAppendingを設定します。書き込みの仕方は上書き時と同じですが、追記モードで開いているため既存のファイルの内容を残したまま最下段に追記書き込みされます。
このようにファイルの操作は、ファイルを開く際の引数の指定方法によってそれ以降に可能な操作が変わります。
また、矛盾がある操作はできません。例えば、読み込みモードでファイルを開いているのに書き込みをしようとしても出来ません。
ファイル操作で大事なのは、確実にファイルを閉じることです。サンプルでは3回開いていますが毎回閉じています。開くことよりも、読み書きをすることよりも、閉じることが一番大事です。その理由は、ファイルは「データを使える」状態にあることが重要だからです。
VBAの場合は関数を抜けるとファイルの閉じ忘れ(Close漏れ)があっても閉じてくれますが、ファイルは他のアプリケーションからも参照することが可能なため、VBAが無限ループするような処理だと、閉じ忘れにより他のアプリケーションからの書き込みが出来ない状況になることもありますので、Closeを書かないようなコードは書かないようにしましょう。
Set Object = Nothingは必要か?
FileSystemObjectの利用が終わった際にオブジェクト変数にNothingを代入するコードを見かけることがあると思います。
こんなのですね。
1 2 3 4 5 |
Dim fso As New FileSystemObject '// 中略 Set fso = Nothing |
でも、関数の最後のNothingの代入はしなくて大丈夫です。というより意味がありません。
Nothingの代入には「オブジェクト変数が参照していた実体への参照を解放する」という意味があります。そのため、実体がなくなるわけではなく単にその実体への参照をしなくなっただけで、再度Setステートメントで元の実体に参照するとまた使えるようになります。
実際にObject型の変数が解放されるのは、関数内のローカル変数であれば関数が終わって変数の役割が終了したときです。
変数のスコープが関数内ではなくモジュール変数として定義されているのであればもちろん話は別ですが、その場合はそもそもNothingを代入して参照を解放すべきかどうかの別の話になります。