VBAでテキストファイルの操作を行うには
VBAでテキストファイルの読み書きを行う場合、特殊な方法を除くと2つの方法があります。
- Open、Close、Input、Line Input、Get、Write、Print、Putステートメントを使う。
- FileSystemObjectクラスを利用する。
用途によってどちらを使うかを決めることになります。
Open等ステートメントはコードが単純ですが、FileSystemObjectクラスにあるような便利な機能はありません。バイナリファイルを扱う場合はこちらを使います。
FileSystemObjectクラスはメソッドやプロパティの使い方に癖がありますが、ファイルの存在をチェックできるメソッドなどの便利なメソッドが用意されています。
ここではOpen等のステートメントを使ったテキストファイルの操作について説明します。
OpenからCloseまでの流れ
テキストファイルを開いてから読み書きを行いファイルを閉じるまでには以下のいずれかの流れになります。
1. 読み込み(通常ファイル)
1.Open → 2.Line Input → 3.Close
2. 読み込み(CSVファイル)
1.Open → 2.Input → 3.Close
3. 書き込み(通常ファイル)
1.Open → 2.Print → 3.Close
4. 書き込み(CSVファイル)
1.Open → 2.Write → 3.Close
Openステートメント
Open Pathname For Mode [Access access] [lock] As [#] Filenumber [Len = reclength]
Openステートメントを使うと既存のテキストファイルを開いたり、新規テキストファイルを作成したりすることが出来ます。
複数の引数がありますが、ほとんどの場合は必須引数の3つ(PathnameとModeとFilenumber)だけを指定すればOKです。
Pathname | 開くテキストファイルのパスをダブルクォーテーションで囲んで指定します。
ドライブ名からファイル名までのフルパスを指定するか、ファイル名だけのどちらかを指定します。 ファイル名だけの場合はカレントフォルダにあるファイルが開かれます。 カレントフォルダはCurDir関数で「CurDir(“C:”)」のようにドライブ名を指定すると調べられます |
|||||||||||||||
Mode | ファイルをどのように開くのかをキーワードで指定します。
シーケンシャル入力、出力モードとはテキストファイルを先頭から終端に向かって読み書きすることを言います。 OutputモードとAppendモードの場合にパスのテキストファイルが存在しない場合はその名前のテキストファイルを新規作成します。 |
|||||||||||||||
Access | ファイルの読み書きを指定します。引数Modeとの組み合わせが不正な場合は構文エラーになります。
たとえば書き込みモードのAppendを指定して読み込みのReadアクセスを指定するなどです。
|
|||||||||||||||
lock | 開いたファイルを他のアプリケーションなどからアクセスできるようにするかどうかの制限を行います。
|
|||||||||||||||
Filenumber | テキストファイルを一意に認識するための番号を#1から#511の値で指定します。
1ファイルしか扱わないのであれば「#1」としても構いません。 |
|||||||||||||||
reclength | Randamモードを指定した場合は読み書きを行うデータ長を指定します。
それ以外の場合は読み書きを行う変数サイズをInteger型の範囲内(32767以下)で指定します。 |
Filenumberの指定
引数Modeが書き込みを行う「Output」または「Append」の場合、同じテキストファイルを異なるファイル番号で開こうとしても、先に開いた方に書き込み権限があるためエラーとなり開けません。
引数Modeが「Input」「Binary」「Random」の場合、同じテキストファイルを異なるファイル番号で開くことが可能です。
ただ、いずれにしてもよほどのことが無い限り、同じテキストファイルに対して複数のアクセスを同時に行うようなことは避けた方が無難です。
FreeFile関数
FreeFile関数はテキストファイルを開く際のOpenステートメントで使うことが出来るファイル番号を返します。
ファイル番号が重複しないのであればFreeFile関数を使わずに#1などと書いても構いません。
Closeステートメント
Close #Finenumber
CloseステートメントはOpenステートメントで開かれたファイルを閉じます。
Closeステートメントで閉じられた際のファイル番号は次のテキストファイルのOpenステートメントで使うことが出来るようになります。
Filenumber | Openステートメントで指定したファイル番号を指定します。
複数のファイル番号を指定することで一度に複数のファイルを閉じることが可能です。 また、ファイル番号を省略した場合はそれまでにOpenステートメントで開いていたファイルを全て閉じます。 |
開いていないファイル番号をCloseで指定した場合
Openステートメントとは異なるファイル番号をCloseで指定した場合、エラーは発生せず何も閉じられることなくCloseステートメントは終了します。
手書きで「#1」などとファイル番号を書いている場合にはファイルが閉じられないバグになります。
EOF関数
EOF関数はOpenステートメントでInputモードかRandomモードで開いたテキストファイルの読み込み位置がファイルの終端(End Of File)に達しているかを判定する関数です。
ファイル終端に達している場合はTrueを返し、そうでない場合はFalseを返します。
引数にOpenステートメント時に指定したファイル番号を設定します。
通常はDo Untilループ条件として利用します。
Line Inputステートメント(1行読み込み用)
Line Input #Filenumber , varname
Filenumber | Openステートメントで指定したファイル番号を指定します。 |
varname | 読み込んだテキストファイルの行データを格納する変数を指定します。
変数の型はVariant型かString型のいずれかです。 |
Line InputステートメントはOpenステートメントでInputモードで開いたテキストファイルを改行コード(CRLF、LF、CRのいずれか)までの行単位で読み込みます。
次に読み込むときは次の行の先頭からになります。
改行コード自体は読み込んだデータには含まれません。
EOF(End Of File)まで読み込み可能ですが、それ以上読み込みを行うとエラーになります。
そのためEOF関数を使ってファイル終端かどうかをチェックする必要があります。
Inputステートメント(CSV読み込み用)
Input #Filenumber, Varlist, ・・・
Filenumber | Openステートメントで指定したファイル番号を指定します。 |
Varlist | 読み込む文字列を指定します。 |
Inputステートメントはテキストファイルからカンマ(,)や改行(CRLF、LF、CRのいずれか)があるまでのデータを読み込みます。
読み込んだあとに再度Inputステートメントを使うと次のカンマや改行までが読み込まれます。
引数Varlistを複数指定している場合はカンマが見つかるまでの文字列を各変数に設定します。
InputステートメントはCSVファイルの1項目ずつを読み込む際には適していますが、1行ごとに取得したい場合はLine Inputステートメントの方が適しています。
読み込まれた元のデータがダブルクォーテーションで囲まれていても、Inputステートメントで取得したデータはダブルクォーテーションの囲みは無い状態になります。
読み込む対象のテキストファイルは以下のようなCSVファイルと形式になります。
“aaa”,”bbb”,”ccc”
“1111”,”2222″,”3333″
“aaa”,”bbb”,”ccc”
Line Inputステートメントと同様で、EOF(End Of File)まで読み込み可能ですが、それ以上読み込みを行うとエラーになります。
そのためEOF関数を使ってファイル終端かどうかをチェックする必要があります。
Printステートメント(1行書き込み用)
Print #Filenumber , [ outputlist ]
Filenumber | Openステートメントで指定したファイル番号を指定します。 |
Outputlist | 書き込むデータを指定します。
引数outputlistは以下の構文で構成されます。 |
[ { Spc(n) | Tab [ (n) ] } ] [ expression ] [ charpos ]
Outputlistを構成するSpcとTabとcharposですが、挙動が分かりにくく使い勝手が悪いため使わない方が無難です。
例えばTabですが、タブ文字を書き込むように思いますが実際は空白スペースを書き込みます。
また、引数nもSpnとTabでは設定する値に際があり、Spnは引数nの数だけスペースを書き込みますが、Tabは引数nから1引いた数のスペースを書き込みます。
こういうのは個人的には触りたくないので使わないようにしています。
書き込みたい文字列を事前に編集して、expressionとしてそれを渡す方が柔軟なコードになります。
Writeステートメント(CSV書き込み用)
Write #Filenumber, Outputlist, ・・・
Filenumber | Openステートメントで指定したファイル番号を指定します。 |
Outputlist | 書き込むデータを指定します。
複数書き込む場合はカンマで区切って指定します。 |
WriteステートメントはOpenステートメントでOutputモードやAppendモードで開かれたテキストファイルにCSVファイル形式のデータを書き込みます。
書き込まれたデータはダブルクォーテーションで囲まれます。データ間はカンマで区切られます。
1行単位の書き込みはPrintステートメントの方が適しています。
サンプルコード
行単位で追加書き込みのサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Sub TextfileAppendTest() Dim n Dim s Dim ar() Dim i s = "C*\test\a.txt" ReDim ar(3) ar(0) = "aaa" ar(1) = "bbb" ar(2) = "ccc" ar(3) = "ddd" '// ファイル番号取得 n = FreeFile '// 追加モードでファイルを開く Open s For Append As #n '// 配列ループ For i = 0 To UBound(ar) '// 配列要素をタブ文字に続けて書き込み Print #n, vbTab & ar(i) Next '// ファイルを閉じる Close #n End Sub |
行単位で読み込むサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Sub TextfileLineInputTest() Dim n Dim s Dim v s = "C*\test\a.txt" '// ファイル番号取得 n = FreeFile '// シーケンシャル入力モードでファイルを開く Open s For Input As #n '// 配列ループ Do Until EOF(n) Line Input #n, v Debug.Print v Loop '// ファイルを閉じる Close #n End Sub |
CSVファイル形式で書き込むサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Sub CsvWriteTest() Dim s Dim n s = "C*\test\a.txt" '// ファイル番号取得 n = FreeFile '// シーケンシャル出力モードでファイルを開く Open s For Output As #n '// カンマ区切りデータを書き込み Write #n, "aaa", "bbb", "ccc" Write #n, "ddd" Write #n, "eee" Write #n, '// ファイルを閉じる Close #n End Sub |
CSVファイル形式で読み込むサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Sub CsvInputTest() Dim s Dim n Dim v s = "C*\test\a.txt" '// ファイル番号取得 n = FreeFile '// シーケンシャル入力モードでファイルを開く Open s For Input As #n Do Until EOF(n) '// カンマ区切りごとにデータを取得 Input #n, v Debug.Print v Loop '// ファイルを閉じる Close #n End Sub |