VBA・マクロ関連セミナー受講者の方から、
「CSVファイルなどのテキストファイルを読み込むマクロについて、インストラクターのネタ帳でも記事を書いてください!」
という要望をいただいたことがあります。
講座終了後のアンケートでも、
「csvデータファイルの読み込みについて伊藤先生だとどう説明していただけるのかなと思っております。」
といったご意見をいただきました。
Openステートメントでテキストファイルを開いて、Do~Loop文の中でLine Input #ステートメントを使って1行ごとにデータを読み込んで、最後に開いていたファイルをCloseステートメントで閉じるという処理について、記事を書いてほしいという要望です。
書籍はもちろん、ネット上にもたくさんのサンプルが存在するので、今さら私が記事を書く必要性もないかなと思っていたのですが、ネット上のサンプルをあらためて眺めてみると、ファイルにアクセスするプログラムに慣れてない方にとっては、難しく感じられるコードの書き方をしているケースが少なくないようですので、記事にしておきます。
テキストファイルを読み込んでイミディエイトウィンドウに出力するサンプルマクロ
実務で本当に必要としているのは、TSV形式やCSV形式のテキストファイルのデータを読んで、いずれかのワークシートに書き込む処理だと思いますが、まずは、テキストファイルを読み込んで、イミディエイトウィンドウに出力するだけのマクロから理解しましょう。
この件に限らず、難しいと感じる処理は、できるだけシンプルな形にして理解するのが鉄則です。
読み込んだデータをワークシートに書き込む処理、読み込むファイルを指定する部分、読み込むテキストファイルがCSV形式で「,」(カンマ)がデータに含まれていたときにどうするかなどは、以下のマクロを納得できたあとに理解しましょう。
Const F_PATH = "c:\tmp\sample.txt"
Dim f_num As Integer ' ファイル番号
Dim rcd As String ' テキストファイルの1行分文字列(1レコード) f_num = FreeFile
Open F_PATH For Input As f_num
Do Until EOF(f_num)
Line Input #f_num, rcd
Debug.Print rcd
Loop
Close f_num
End Sub
上記のマクロを実行すると、定数・F_PATHに指定した「c:\tmp\sample.txt」ファイルが読み込まれ、
Open F_PATH For Input As f_num
1行ずつイミディエイトウィンドウに出力されます。
Do Until EOF(f_num)
Line Input #f_num, rcd
Debug.Print rcd
ネットなどでよく見かけるマクロ
同じことを行うのに、ネットでは以下のような書き方をしている例を、よく見かけるように感じています。
Sub テキストファイルの読み込み_ネットで見かける例()
Const F_PATH = "c:\tmp\sample.txt"
Dim rcd As String Open F_PATH For Input As #1
Do Until EOF(1)
Line Input #1, rcd
Debug.Print rcd
Loop
Close #1
End Sub
先にご紹介したマクロと何が違うかというと、読み込み処理で利用するファイル番号をFreeFile関数を使って取得するのか「1」と直値を書いているのかという点と、もう一つはそのファイル番号を指定するときに「#」記号をどこで使っているかです。
ファイル番号をFreeFile関数で取得する
テキストファイルの読み込み処理に慣れていないと、
Open F_PATH For Input As #1
といったコードを見たときに「#1」の「1」が気になって仕方ない、という事態に陥ります。
なぜ「1」なのだろう、「1」で決め打ちをしていて問題になることはないのだろうか、といった疑問を感じる方がいらっしゃいます。
この「1」が気になる方向けに、先のマクロでは、
Dim f_num As Long
f_num = FreeFile
Open F_PATH For Input As f_num
のように、VBAのFreeFile関数を使ってファイル番号を取得するようにしています。
これならば「1」を気にする必要はないはずです。
ちなみに、FreeFile関数で返される値を調べてみれば、ほとんどのケースで実は「1」が返されることがわかり、ネット上でよく見かける「1」を直接書いているコードでも、結局は問題ないことを理解していただけるはずです。
#記号が必要なのはLine Input #ステートメントだけ
次にファイル番号につく「#」記号です。
ネットなどで見かけるコードの場合、ファイル番号を使っているのは、以下の4か所ですが、
Open F_PATH For Input As #1
Do Until EOF(1)
Line Input #1, rcd
Close #1
厄介なのは「#」の不要な箇所と必要な箇所が混在していることです。
ファイル番号には、
絶対に「#」をつけてはいけない箇所と、
絶対に「#」をつけなければならない箇所があります。
絶対に「#」をつけてはいけないのは、
Do Until EOF(1)
の部分です。
逆に絶対「#」をつけなければならないのは、
Line Input #1, rcd
の部分です。
ファイルを開く、
Open F_PATH For Input As #1
と、ファイルを閉じる
Close #1
については、実は「#」があってもなくてもOKなのです。
Openステートメントのヘルプには、
Open pathname For mode [Access access] [lock] As [#]filenumber [Len=reclength]と、省略可能であることを示す[ ]の中に「#」が記述されています。
しかし、どういうわけだかネットではOpenステートメント・Closeステートメントともに「#」をつけているケースのほうを圧倒的に見かけます。
ですが私は、絶対に必要な箇所にだけ「#」をつけるコードにしておくほうが、理解しやすいと感じています。
つまり、ネットでよく見かける、
Open F_PATH For Input As #1
Do Until EOF(1)
Line Input #1, rcd
Debug.Print rcd
Loop
Close #1
のようなコードではなく、
Open F_PATH For Input As 1
Do Until EOF(1)
Line Input #1, rcd
Debug.Print rcd
Loop
Close 1
という書き方をするということです。
このコードを「1」という直値を使うのではなく、FreeFile関数の戻り値を格納した変数・f_numを使って書いたのが、
Open F_PATH For Input As f_num
Do Until EOF(f_num)
Line Input #f_num, rcd
Debug.Print rcd
Loop
Close f_num
です。
いかがでしょう。
「#」があちこち出てくるより、「#」を絶対必要とするLine Input #ステートメントの1箇所にしか出てこないほうが、理解するときの負荷が下がると感じられませんか。
OpenステートメントやCloseステートメントでも「#」を書くコードにすっかり慣れてしまっている方は、「#」がLine Input #ステートメントにしか出てこないと、気持ち悪く感じるのかもしれませんが...
ファイル読み込み処理について、慣れない方が疑問を感じる箇所は他にもありますが、この記事ではファイル番号に関連した部分だけ取り上げました。
Home » エクセルマクロ・Excel VBAの使い方 » マクロのサンプル » VBAでテキストファイル・CSVファイルを読み込むには-Openステートメント・Line Input #ステートメント