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つの変数なのでここでも繰り返しはありません。
VBAはどうやって覚える?
プログラムのコードが読めないと、参考にしているコードの理解や自分でプログラムを書くときに時間がかかってしまいます。そんな時は基礎から学ぶと応用もできるようになり自分の作りたいプログラムがスムーズに作れるようになります。
無料でやるならネット上の学習サイトを参考にするといいです。
こちらはVBAの基礎から説明している無料のWEBサイトになります。
>>基礎から学べるWEBサイトを見てみる
過去にネットでの学習でつまずいた方には専門書をオススメします。
本なら基礎から学べる事はもちろん、読者視点で分かりやすい解説になっています。
一人で集中してコツコツ進めたい方は書籍を試してください。
本を読んでもわからない所が多すぎたり、誰かに質問したい場合はオンラインスクールを見てみましょう。
カウンセリングから目的に応じた学習プランと教材を提供してくれるので、プログラミングの敷居がとても低くなります。
誰かに相談できるのは心強いです。
>>オンラインスクールを無料体験で始める
最後に
私が初めてテキストファイルの操作をした時はテキストの内容を1行ずつ読み込んでセルや配列に格納していました。
でも実はVBAの処理としてはセルの読み書きが一番時間がかかるんですね。
データの移動はセルでも配列でも一括でドンとやるのが早いです。
セルに入れるデータが10行や100行であれば一瞬ですが数万行とかになると数秒から数十秒の待ち時間が出てきて試しにポンっと叩くのも億劫になってしまいます。
なので今回テキストファイルの内容をまとめて配列に入れて、配列の内容をまとめてセルに反映させる方法を説明しました。型を覚えてしまえば一括ドンも簡単にできるのでぜひ使ってみてください。