今回はVBAを使用したCSVデータの一括読み込み方法について紹介していきたいと思います。
CSVデータをExcelに読み込む場合、単純にCSVデータをダブルクリックすればExcelアプリケーションが自動的に起動して、Excelデータとして開くことができると思います。
しかし、その場合のよくあるトラブルとしては、以下になります。
- 文字化け
- 同一セルに複数のデータが入る(本来は1セル1データにしたいところ)
- 表示形式のトラブル(0001が1になったり)※文字列が数値になる等
- データ自体にダブルクォーテーション、カンマが入っていることによるデータ加工の必要性
などではないでしょうか。
そういった場合は、VBAの使用、エクセル機能(テキストファイルウィザード、パワークエリなど)が考えられます。
上記のトラブル回避には、それなりのスキルが必要となってきます。
今回の記事では、VBAを活用した基本的なCSVデータの読み込み方法から文字化け対策やCSV複数データ一括読込を紹介していきたいと思います。
関連記事はこちら
パワークエリを使った最も手っ取り早いテーブル結合方法についてはこちら↓
「4、データ自体にダブルクォーテーション、カンマが入っていることによるデータ加工の必要性」についての記事はこちら↓
CSVファイル3つを一括してエクセルに読み込む
CSVファイルの3ファイルを一括してエクセルファイルに読み込んでみたいと思います。(インプット先のエクセルと同一フォルダ内の「うまい棒一覧データ」を読み込みます。)
3つCSVファイルには上記のように日付ごとのデータが入っています。
大まかなコードの流れ(方法)
- Dir関数を使用して3つのファイルを順番に取得
- Openステートメント、Line Input #ステートメントで受け取ったファイルを1行ずつ読み込む
Sub CSV読み込み()
Dim file, file2 As String
Dim buf As String
Dim arrybuf As Variant
Dim flag As Boolean
Dim i As Integer
i = 2
file = Dir(ThisWorkbook.Path & "\*.csv") '読込先エクセルと同一フォルダのテキストファイルのデータを取得
Do While file <> ""
file2 = ThisWorkbook.Path & "\" & file 'フルパスを変数に格納
Open file2 For Input As #1 'ファイルをインプットモードで#1に入れる
flag = True 'タイトル行を除くためフラグを立てる
Do Until EOF(1) '最終行まで行ったらループを抜ける
Line Input #1, buf '1行をbuf変数にいれる
arrybuf = Split(buf, ",") '1行分のデータを配列に格納
If flag Then 'フラグがTRUEの場合
flag = False 'フラグをフォルスにする(タイトル行をスキップするため)
Else
Sheet1.Cells(i, 1).Resize(, 4).Value = arrybuf '2行目以降をエクセルに入れていく
i = i + 1
End If
Loop '次の行にいくためのループ
Close #1 'ファイルを閉じる
file = Dir() '次のファイルに移行
Loop '次のファイルに行くためのループ
End Sub
Dir関数(ファイルが存在するかどうかを判定する関数でファイル名を返します。)
file = Dir(ThisWorkbook.Path & "\*.csv") '読込先エクセルと同一フォルダ内のテキストファイルのデータを取得
【書式】
=Dir(ファイル名やフォルダ名の文字列式、取得するファイルの属性)
【属性】 | 値 | 内容 |
vbNormal | 0 | 標準ファイル |
vbHidden | 2 | 隠しファイル |
vbSystem | 4 | システムファイル |
vbVolume | 8 | ボリュームラベル |
vbDirectory | 16 | フォルダ |
文字列式をワイルドカード(アスタリスク)にすることで、このフォルダの中のファイル名を返すということになります。今回の場合は文字列式部分が、
= Dir(ThisWorkbook.Path & "\*.csv")
フォルダ内のCSVファイルをすべてを返すという意味になります。
(フルパスを入力しますが、返り値はあくまでファイル名です。)
Openステートメント、Line Input #ステートメント
読み込みたいファイルを指定して、1行ずつ読み込みます。
Open file2 For Input As #1 'ファイルをインプットモードで#1に入れる
open ファイルフルパス for 開き方 as #〇
#については、ファイルをファイル番号#(ナンバー1~511)に入れておくというイメージです。
(1~511の番号を指定します。)そうすることで以降#ナンバーをファイルとみなしてコードが進んいきます。
今回は読み込みなので、開き方=inputとします。主な開き方は以下のなります。
Input | 入力モード | 読み込み |
Output | 出力モード | 書き込み |
Append | 追加モード | 書き込み |
Outputモード・Appendモードはエクセルデータをテキストファイルなどにに書き出す場合に使います。Outputは書き出し先が上書きされ、Appendについては追記になります。
InputやOutputなどエクセル側から見た表現ですね。
Line Input #ステートメント
Line Input #1, buf '1行をbuf変数にいれる
Line Input #〇,buf
#〇(ファイルパス)の中のデータの1行を変数(buf)に入れます。
その他のコード解説
arrybuf = Split(buf, ",") '1行分のデータを配列に格納
先ほど、1行分のデータをbuf変数に入れましたが、このままではエクセルのセル1つに1行すべてのデータが入ってしまうので、配列変数に入れ直します。
Sheet1.Cells(i, 1).Resize(, 4).Value = arrybuf
1行のデータの数のセル数(4列分)を指定して、配列変数のデータをセルに入れます。
タイトル行(1行目)除外の動作
タイトル行(1行目)はエクセルへ入力しないように、各ファイル2行目から入るようにします。
下記はタイトル行取得時のコードの動作です。
Line Input #1, buf 'タイトル行が変数に入ります。
arrybuf = Split(buf, ",") 'タイトル行のデータを配列に格納
If flag Then 'flagはTrueなので、flagはフォルスになるのみで、次の行の読み込みループに移行します。
flag = False 'フラグをフォルスにする(タイトル行をスキップするため)
Else
1行分のデータ数の可変
上記のようにデータによっては1行あたりのデータが4つと限らない場合があります。4月1日、4月6日には「よっちゃんいか」が入っていますね。
Sheet1.Cells(i, 1).Resize(, UBound(arrybuf) + 1).Value = arrybuf
Resizeプロパティの列数にUBound関数を入れることで対応できます。
UBound関数は配列の最大インデックスを返します。つまり、1行ごとに配列データを作っているので、1行ごとの最大インデックスを返してくれます。(+1にしているのは、配列のインデックスは0から始まるので1をプラスしています。)
数値データ(補足)
CSVファイルに0から始まる数値が含まれている場合(商品コード:0001)でも、0が省かれることなく転記してくれます。(配列をまとめてセルに入れる場合、全て文字列として入ります。)
CSVファイル読み込みのためのADOの使い方↓
まとめ
CSV読込のためのOpenステートメント、Line Input #ステートメントを使ったコードを紹介しました。もっとも基本的なコードだと思います。
次回は、ファイルシステムオブジェクトText Streamオブジェクトを使った方法を紹介します。
コメント