カテゴリー: TextStream

Excel VBAでテキストファイルへのアクセスを行うためのTextStreamオブジェクトについて調べたことを記載していきます
CSVファイルの操作もTextStreamオブジェクトを利用して、簡単に処理が行えます

  • VBA TextStreamの使い方完全ガイド!ファイル読み書きとプロパティ解説

    VBA TextStreamの使い方完全ガイド!ファイル読み書きとプロパティ解説

    テキストファイルの読み書きを行うためのTextStreamオブジェクトの操作について、いくつかのサンプルを作成しながら勉強していきます!

    TextStreamオブジェクトを作成する方法は、以下の記事が参考になりますので、そちらを見てください!(手抜きじゃないよw)

    https://zesys.net/excel/filesystemobject/method-createtextfile/

    ■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オブジェクトを生成します

    VB
    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オブジェクトを生成します

    VB
    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:呼び出し元関数のサンプル

    VB
    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型になることに注意してください

    VB
    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のサンプル

    VB
    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が参照設定されているかどうかは関係ありませんからねー

    VB
    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メソッドに揃えていきます

    ④:呼び出し元関数のサンプル

    VB
    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だからきっと文字数の指定なのだと思いますが、確認していきます

    ⑤:呼び出し元関数のサンプル

    VB
    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メソッドで指定できる数について確認しています
    出力結果は以下のようになります

    VB
    -----
    Line = 1Column = 1        [あ1]
    Line = 1Column = 3
    Line = 1Column = 4
    -----
    Line = 1Column = 4        [3い]
    Line = 1Column = 6
    Line = 1Column = 7
    -----
    Line = 1Column = 7        [23]
    Line = 1Column = 9
    Line = 1Column = 10
    -----
    Line = 1Column = 10       [
    ]
    Line = 2Column = 1
    Line = 2Column = 2
    -----
    Line = 2Column = 2        [2う]
    Line = 2Column = 4
    Line = 2Column = 5
    -----
    Line = 2Column = 5        [2え]
    Line = 2Column = 7
    Line = 2Column = 8
    -----
    Line = 2Column = 8        [
    ]
    Line = 3Column = 1
    Line = 3Column = 2
    -----
    Line = 3Column = 2        [
    1]
    Line = 4Column = 2
    Line = 4Column = 3
    -----
    Line = 4Column = 3        [3か]
    Line = 4Column = 5
    Line = 4Column = 6
    -----
    Line = 4Column = 6        [5き]
    Line = 4Column = 8
    Line = 4Column = 9
    -----
    Line = 4Column = 9        [くけ]
    Line = 4Column = 11
    Line = 4Column = 12
    -----
    Line = 4Column = 12       [8こ]
    Line = 4Column = 14
    Line = 4Column = 15
    -----
    Line = 4Column = 15       [
    ]
    Line = 5Column = 1
    Line = 5Column = 2
    -----
    Line = 5Column = 2        [
    
    ]
    Line = 6Column = 2
    Line = 7Column = 1
    -----
    

    ・説明

    ④を見てもわかるように、想像していた「ReadLineメソッドの場合に、AtEndOfLineプロパティを使う」というのは外れていますねw

    AtEndOfLineは、空行で止まることがわかったが、この後、何をすればいいんだろうか?謎が深まるw

    ⑤のサンプルの実行結果を見る限り、引数で指定できるのはバイト数ではなく、文字数であることがわかりますね!
    改行コードも1文字としてカウントされていることがわかります

    ・注意点

    • AtEndOfLineプロパティの使い道がわからんw
    • TestStreamオブジェクトには、読み取り専用か、書き込み専用かのプロパティを持っていない
    • 読み取り専用でも(ファイルポインタの)現在地はわかるが、先頭に戻ることはできない
    • 書き込み専用でも保存するメソッドはない(Closeメソッド?)
    • 書き込み専用ではプロパティへのアクセスは許可されていない
    • ReadメソッドもSkipメソッドもAtEndOfStreamプロパティを確認してから実行すること

    ・その他

    サンプルの中でほぼ全て(ReadAllとSkipLineメソッド以外)のメンバーを使用しましたから、個別に書く必要はなさそうですかね?w

    • ReadAllメソッドは、ファイル全てを読み出すということは、メソッド名からもわかりますね
    • SkipLineメソッドは、引数で指定した行数分を読み飛ばすということは、ReadLineメソッドと比較しても理解できそうですね

    ではでは