TextStreamについて
テキストファイルの読み書きを行うためのTextStreamオブジェクトの操作について、いくつかのサンプルを作成しながら勉強していきます!
TextStreamオブジェクトを作成する方法は、以下の記事が参考になりますので、そちらを見てください!(手抜きじゃないよw)
■TextStreamオブジェクト
テキストファイルへのアクセスを助けてくれるオブジェクトですね!
FileSystemObjectのCreateTextFileメソッドやOpenTextFileメソッドにて取得できるオブジェクトです
・構文
構文は以下の通りです
TextStream. { property | method }
FileSystemObjectから返されたTextStreamオブジェクトに関連づいている任意のプロパティとメソッドを呼び出します
・メソッド
オブジェクトのメソッドは以下の通りです
- Close … 開いているTextStreamファイルを閉じる
- Read … 指定された数の文字をTextStreamファイルから読み取って返す
- ReadAll … TextStreamファイル全体を読み取って返す
- ReadLine … TextStreamファイルから1行を読み取って返す
- Skip … TextStreamファイルを読み込むときに、指定された数の文字を読み飛ばす
- SkipLine … TextStreamファイルを読み取るときに次の行を読み飛ばす
- Write … 指定されたテキストをTextStreamファイルに書き込む
- WriteBlankLines … 指定された数の改行文字をTextStreamファイルに書き込む
- WriteLine … 指定されたテキストと改行文字をTextStreamファイルに書き込む
ファイルアクセスと言えば、読み書きですね!
TextStreamオブジェクトを作るのは、FileSystemObjectのメソッドですが、閉じるときは、作成したTextStreamオブジェクトのCloseメソッドで閉じます
いつも気になりますが、ReadメソッドやSkipメソッドで書かれている「指定された数の文字」というのは、文字数なの?バイト数なの?と・・w
・プロパティ
オブジェクトのプロパティは以下の通りです
- AtEndOfLine … ファイルポインタがTextStreamファイルの行末の直前にあるかどうか
- AtEndOfStream … ファイルポインタがTextStreamファイルの末尾にあるかどうか
- Column … 入力ストリームの現在の文字位置の列番号を返す
- Line … TextStreamファイルの現在の行番号を返す
AtEndOfLine プロパティとAtEndOfStreamプロパティの違いがいまいちわかっていませんw
行単位アクセスのReadLineメソッドを使う場合は、AtEndOfLine プロパティなのかな?
文字単位アクセスのReadメソッドを使う場合は、AtEndOfStream プロパティなのかな?
サンプルでその辺りを見ていきたいと思います
■例
・簡単なサンプル(参照設定あり)
①-1:CreateTextFileのサンプル
FileSystemObjectを作成し、CreateTextFileメソッドで新規ファイルのフルパスを指定して、新しいTextStreamオブジェクトを生成します
Sub CreateTextFile_Sample(filespec As String, oText As TextStream) Dim obj As FileSystemObject ' オブジェクトを作成 Set obj = New FileSystemObject ' TextStream(新規ファイルを作成) Set oText = obj.CreateTextFile(filespec, True, False) ' オブジェクトを破棄 Set obj = Nothing End Sub
①-1では、新規ファイルを作成する場合に、作成したファイルの書き込み用のTextStreamオブジェクトを [oText] に取得しています
②-1:OpenTextFileのサンプル
FileSystemObjectを作成し、OpenTextFileメソッドで既存ファイルのフルパスを指定して、新しいTextStreamオブジェクトを生成します
Sub OpenTextFile_Sample(filespec As String, oText As TextStream) Dim obj As FileSystemObject ' オブジェクトを作成 Set obj = New FileSystemObject ' TextStream(既存ファイルを開く) Set oText = obj.OpenTextFile(filespec, ForReading, False, TristateFalse) ' オブジェクトを破棄 Set obj = Nothing End Sub
②-1では、既存ファイルを開いた場合に、読み取り可能なTextStreamオブジェクトを[oText] に取得しています
③-1:呼び出し元関数のサンプル
Sub CallTextStream_Sample() Dim oText As TextStream Dim filespec As String Dim buf As String ' TextStreamファイルパス filespec = "E:\VBA\Sample001\Sample.txt" ' ①-1:ファイルを作成する関数を呼び出す Call CreateTextFile_Sample(filespec, oText) With oText ' ファイルに書き込む Call .WriteLine("AAAAA") Call .WriteLine("BBBBB") Call .WriteLine("CCCCC") Call .WriteLine("DDDDD") Call .WriteLine("EEEEE") ' 空行を3行書き込む Call .WriteBlankLines(3) ' 閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oTxt = Nothing ' ②-2:ファイルを読み込む関数を呼び出す Call OpenTextFile_Sample(filespec, oText) With oText ' ファイルの最後まで読み込む Do Until .AtEndOfStream ' 行番号と一行(改行コードまで)読み込む Debug.Print .Line, .ReadLine Loop ' フィルを閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing End Sub
参照設定を使用したサンプル①-1と②-1を呼び出して、ファイルへの書き込みとファイルからの読み出しを行っています
・簡単なサンプル(参照設定なし)
上記の参照設定ありのサンプルを参照設定なしで書き直してみます
FileSystemObjectも引数でもらえばスッキリします(多くの人がその方法を選ぶでしょうw)
ただ、その場合、関数化の意味もほとんどなくなりますけどねw
①-2:CreateTextFileのサンプル
参照設定を使用しない場合、引数のTextStreamオブジェクトもObject型になることに注意してください
Sub CreateTextFile_Sample2(filespec As String, oText As Object) Dim obj As Object ' オブジェクトを作成 Set obj = CreateObject("Scripting.FileSystemObject") ' TextStream Set oText = obj.CreateTextFile(filespec, True, False) ' オブジェクトを破棄 Set obj = Nothing End Sub
②-2:OpenTextFileのサンプル
Sub OpenTextFile_Sample2(filespec As String, oText As Object) Dim obj As Object ' オブジェクトを作成 Set obj = CreateObject("Scripting.FileSystemObject") ' TextStream Set oText = obj.OpenTextFile(filespec, ForReading, False, TristateFalse) ' オブジェクトを破棄 Set obj = Nothing End Sub
③-2:呼び出し元関数のサンプル
③-1とほとんど変わりなく作成することができます
これこそがCreateTextFileメソッドやOpenTextFileメソッドを関数化して呼び出すことの価値です!
ファイルを作成や開いて、読み書きすることに、FileSystemObjectが参照設定されているかどうかは関係ありませんからねー
Sub CallTextStream_Sample2() Dim oText As Object Dim filespec As String Dim buf As String ' TextStreamファイルパス filespec = "E:\VBA\Sample002\Sample.txt" ' ①-2:ファイルを作成する関数を呼び出す Call CreateTextFile_Sample2(filespec, oText) With oText ' ファイルに書き込む Call .WriteLine("AAAAA") Call .WriteLine("BBBBB") Call .WriteLine("CCCCC") Call .WriteLine("DDDDD") Call .WriteLine("EEEEE") ' 空行を3行書き込む Call .WriteBlankLines(3) ' 閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing ' ②-2:ファイルを読み込む関数を呼び出す Call OpenTextFile_Sample2(filespec, oText) With oText ' ファイルの最後まで読み込む Do Until .AtEndOfStream ' 行番号と一行(改行コードまで)読み込む Debug.Print .Line, .ReadLine Loop ' フィルを閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing End Sub
出力結果としては①-1、②-1、③-1も、①-2、②-2、③-2も同じになります
・AtEndOfStreamとAtEndOfLineの違い
プロパティで気になったAtEndOfLineとAtEndOfStreamの違いを確認していきますが、使用するのはReadLineメソッドに揃えていきます
④:呼び出し元関数のサンプル
Sub CallTextStream_Sample3() Dim oText As TextStream Dim filespec As String Dim buf As String ' TextStreamファイルパス filespec = "E:\VBA\Sample003\Sample.txt" ' ①-1:ファイルを作成する関数を呼び出す Call CreateTextFile_Sample(filespec, oText) With oText ' ファイルに書き込む Call .WriteLine("AAAAA") Call .WriteLine("BBBB") Call .WriteBlankLines(1) ' 空行 Call .WriteLine("CCC") Call .WriteBlankLines(1) ' 空行 Call .WriteLine("DDDD") Call .WriteLine("EEEEE") Call .WriteBlankLines(1) ' 空行 ' 閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing ' ②-2:ファイルを読み込む関数を呼び出す Call OpenTextFile_Sample(filespec, oText) With oText Debug.Print "===== AtEndOfStream =====" Do Until .AtEndOfStream ' 行番号と一行(改行コードまで)読み込む Debug.Print .Line, .ReadLine Loop ' フィルを閉じる Call .Close End With ' ②-2:ファイルを読み込む関数を呼び出す Call OpenTextFile_Sample(filespec, oText) With oText Debug.Print "===== AtEndOfLine =====" Do Until .AtEndOfLine ' 行番号と一行(改行コードまで)読み込む Debug.Print .Line, .ReadLine Loop ' フィルを閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing End Sub
④の出力結果
出力結果を見てみましょう!
AtEndOfStreamではファイルの最後まで読み込むことができましたが、AtEndOfLineでは最初の空行の直前で止まってしまい、ファイルを最後まで読み込むことができませんでした
AtEndOfLineは思っていた動きとかなり違いがありました
1行毎に終了するのかと思っていたので、空行で終了したことが驚きです
・ReadとSkipを試す
ReadとSkipでは数を指定できるとあります
VBAだからきっと文字数の指定なのだと思いますが、確認していきます
⑤:呼び出し元関数のサンプル
Sub CallTextStream_Sample4() Dim oText As TextStream Dim filespec As String Dim buf As String ' TextStreamファイルパス filespec = "E:\VBA\Sample004\Sample.txt" ' ①-1:ファイルを作成する関数を呼び出す Call CreateTextFile_Sample(filespec, oText) With oText ' ファイルに書き込む Call .Write("あ123い1234") Call .WriteBlankLines(1) Call .Write("12う12えお") Call .WriteBlankLines(2) Call .Write("123か45き6くけ78こ9") Call .WriteBlankLines(3) ' 閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing ' ②-2:ファイルを読み込む関数を呼び出す Call OpenTextFile_Sample(filespec, oText) With oText Debug.Print "-----" Do Until .AtEndOfStream ' 行番号と一行(改行コードまで)読み込む Debug.Print "Line = " & .Line & "、Column = " & .Column, "[" & .Read(2) & "]" If (.AtEndOfStream = False) Then Debug.Print "Line = " & .Line & "、Column = " & .Column .Skip (1) Debug.Print "Line = " & .Line & "、Column = " & .Column End If Debug.Print "-----" Loop ' フィルを閉じる Call .Close End With ' TextStreamオブジェクトを破棄 Set oText = Nothing End Sub
ReadメソッドとSkipメソッドで指定できる数について確認しています
出力結果は以下のようになります
----- Line = 1、Column = 1 [あ1] Line = 1、Column = 3 Line = 1、Column = 4 ----- Line = 1、Column = 4 [3い] Line = 1、Column = 6 Line = 1、Column = 7 ----- Line = 1、Column = 7 [23] Line = 1、Column = 9 Line = 1、Column = 10 ----- Line = 1、Column = 10 [ ] Line = 2、Column = 1 Line = 2、Column = 2 ----- Line = 2、Column = 2 [2う] Line = 2、Column = 4 Line = 2、Column = 5 ----- Line = 2、Column = 5 [2え] Line = 2、Column = 7 Line = 2、Column = 8 ----- Line = 2、Column = 8 [ ] Line = 3、Column = 1 Line = 3、Column = 2 ----- Line = 3、Column = 2 [ 1] Line = 4、Column = 2 Line = 4、Column = 3 ----- Line = 4、Column = 3 [3か] Line = 4、Column = 5 Line = 4、Column = 6 ----- Line = 4、Column = 6 [5き] Line = 4、Column = 8 Line = 4、Column = 9 ----- Line = 4、Column = 9 [くけ] Line = 4、Column = 11 Line = 4、Column = 12 ----- Line = 4、Column = 12 [8こ] Line = 4、Column = 14 Line = 4、Column = 15 ----- Line = 4、Column = 15 [ ] Line = 5、Column = 1 Line = 5、Column = 2 ----- Line = 5、Column = 2 [ ] Line = 6、Column = 2 Line = 7、Column = 1 -----
・説明
④を見てもわかるように、想像していた「ReadLineメソッドの場合に、AtEndOfLineプロパティを使う」というのは外れていますねw
AtEndOfLineは、空行で止まることがわかったが、この後、何をすればいいんだろうか?謎が深まるw
⑤のサンプルの実行結果を見る限り、引数で指定できるのはバイト数ではなく、文字数であることがわかりますね!
改行コードも1文字としてカウントされていることがわかります
・注意点
- AtEndOfLineプロパティの使い道がわからんw
- TestStreamオブジェクトには、読み取り専用か、書き込み専用かのプロパティを持っていない
- 読み取り専用でも(ファイルポインタの)現在地はわかるが、先頭に戻ることはできない
- 書き込み専用でも保存するメソッドはない(Closeメソッド?)
- 書き込み専用ではプロパティへのアクセスは許可されていない
- ReadメソッドもSkipメソッドもAtEndOfStreamプロパティを確認してから実行すること
・その他
サンプルの中でほぼ全て(ReadAllとSkipLineメソッド以外)のメンバーを使用しましたから、個別に書く必要はなさそうですかね?w
- ReadAllメソッドは、ファイル全てを読み出すということは、メソッド名からもわかりますね
- SkipLineメソッドは、引数で指定した行数分を読み飛ばすということは、ReadLineメソッドと比較しても理解できそうですね
ではでは