VBAでテキストファイルから入力や出力する操作

VBA

forで1行ずつ処理するのではなくまとめて値を渡す方式で書いてみた。

きっかけはforよりシンプルな書き方が無いかなと思ったからです。

テキストファイルからエクセルへ

ファイルから入力するメインプログラム

Sub ファイルから入力()
    検索パス = ThisWorkbook.Path
    検索ファイル名 = "入力データ.txt"
    
    '①テキストファイルを探す
    ファイルパス = ファイルパス取得(検索パス, 検索ファイル名)
    If ファイルパス = Empty Then
        MsgBox "ファイルが存在しません"
        Exit Sub
    End If
    
    '②テキストファイルの内容を読み込む
    ファイルの内容 = ファイルの内容を配列へ格納(ファイルパス)
    
    '③読み込んだ内容をエクセルに貼り付ける
    ファイルの行数 = UBound(ファイルの内容) + 1
    ファイルの内容2次配列 = WorksheetFunction.Transpose(ファイルの内容)
    Range("A1:A" & ファイルの行数) = ファイルの内容2次配列
End Sub

途中に2つの関数を呼び出す。

  • ファイルパス取得

フォルダパスとファイル名を渡すとファイルを検索して存在した場合はフルパスが返ってくる関数

  • ファイルの内容を配列へ格納

ファイルパスを渡すとファイルの内容を読み込んで行毎に区切って配列で返ってくる関数

大事な所は最後のWorksheetFunction.Transposeでこれは1次配列をセルに貼り付けできる2次配列に切り替えています。

これによって配列のデータでも直接セルに貼り付けができるのでforによるループを使わなくても良いと言うことになります。

ファイル取得関数

Function ファイルパス取得(パス, ファイル名)
    Set FSO = CreateObject("Scripting.FileSystemObject")
    
    For Each ファイル In FSO.GetFolder(パス).Files
        If ファイル.Name Like ファイル名 Then
            ファイルパス取得 = ファイル.Path
        End If
    Next
End Function

FSOというファイルシステムオブジェクトを作り検索するパスを指定してそのファイル名のリストを取得しています。

取得したファイル名のリストをファイルに格納して探しているファイル名と比較しています。

一致したらファイル名のフルパスを戻り値として渡します。

ファイルを開き全行を配列へ格納

Function ファイルの内容を配列へ格納(ファイルパス)
    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set テキストファイル = FSO.OpenTextFile(ファイルパス)
    ファイルの内容を配列へ格納 = Split(テキストファイル.ReadAll, vbLf)
    テキストファイル.Close
End Function

データの入っているファイルをテキストファイルというオブジェクとして作成して、ReadAllメソッドで全ての内容を取得しています。

そのままだと1つの変数に格納されベタ貼り状態になってしまうので、Split関数で改行(vbLf)毎に要素を分ける事で配列に変換して戻り値として渡します。

エクセルからテキストファイルへ

ファイルへ出力するメインプログラム

Sub ファイルへ出力()
    Const はい As Long = 6
    出力フォルダパス = ThisWorkbook.Path
    出力ファイル名 = "出力データ.txt"
    最終行 = Cells(Rows.Count, 1).End(xlUp).Row
    
    '①テキストファイルを探す
    ファイルパス = ファイルパス取得(出力フォルダパス, 出力ファイル名)
    If Not ファイルパス = Empty Then
        result = MsgBox("出力ファイル名と同じファイルが存在します。削除して進めますか?", vbYesNo + vbQuestion)
        Select Case result
            Case はい
                Kill ファイルパス
            Case Else
                MsgBox "処理を中止します。"
                Exit Sub
        End Select
    End If

    '②エクセルの内容を読み込む
    出力データ2次配列 = Range("A1:A" & 最終行)
    出力データ1次配列 = WorksheetFunction.Transpose(WorksheetFunction.Index(出力データ2次配列, 0, 1))
    出力データ = Join(出力データ1次配列, vbLf)


    '③読み込んだ内容をテキストファイルへ書き込む
    Call テキストファイルに出力(出力フォルダパス, 出力ファイル名, 出力データ)
End Sub

こちらは1つの関数と1つのプログラムを呼び出します。

  • ファイルパス取得

ファイル入力の関数と同じなのでコードは割愛しています。

  • テキストファイルに出力

フォルダパス、ファイル名、データを渡すとそのファイル名のファイルを作成してデータを書き込むプログラム

 

ファイルへ出力する際もファイルが存在するか確認します。

既にファイルが存在する場合は削除して続けるのか、処理を止めるかをメッセージボックスで確認します。

エクセルの内容の読み込みはセルの内容を2次配列として取り出し、それを1次配列→変数へと集約していきます。

そうする事でテキストファイルへ書き込む動作を1回で済ませることができます。

ファイル出力プログラム

Sub テキストファイルに出力(フォルダパス, ファイル名, データ)
    Set FSO = CreateObject("Scripting.FileSystemObject")
    出力フルパス = FSO.BuildPath(フォルダパス, ファイル名)
    Set テキストファイル = FSO.CreateTextFile(出力フルパス)
    
    テキストファイル.Write (データ)
    テキストファイル.Close
End Sub

テキストファイルというオブジェクとして作成して、Writeメソッドで全ての内容を書き込みます。

書き込むデータは改行込みの1つの変数なのでここでも繰り返しはありません。

最後に

私が初めてテキストファイルの操作をした時はテキストの内容を1行ずつ読み込んでセルや配列に格納していました。

でも実はVBAの処理としてはセルの読み書きが一番時間がかかるんですね。

データの移動はセルでも配列でも一括でドンとやるのが早いです。

セルに入れるデータが10行や100行であれば一瞬ですが数万行とかになると数秒から数十秒の待ち時間が出てきて試しにポンっと叩くのも億劫になってしまいます。

なので今回テキストファイルの内容をまとめて配列に入れて、配列の内容をまとめてセルに反映させる方法を説明しました。型を覚えてしまえば一括ドンも簡単にできるのでぜひ使ってみてください。

コメント

タイトルとURLをコピーしました