毎日や毎月届くCSVファイルを、手作業でExcelに貼り付けていませんか。「ファイルを開いて、全選択してコピーして、シートに貼り付けて……」という作業は、地味なわりに時間がかかりますよね。
1ファイルなら数分でも、10ファイル・20ファイルと増えると一気に負担になります。しかもコピペの貼り付け位置を間違えると、データがずれて気づかないこともあります。
そんな繰り返し作業こそ、VBA(マクロ)の出番です。一度コードを書いておけば、ボタン1つでCSVの取り込みが一瞬で終わります。この記事では、CSVを読み込むコードと書き出すコードを、コピペで動く形で順番に紹介します。
VBAでCSVを読み込む・書き出すとは?
VBAでCSVを扱うとは、マクロを使ってCSVファイルの取り込みと出力を自動化することです。読み込みは「CSVの中身をExcelシートに展開する処理」を指します。書き出しは「シートのデータをCSVファイルとして保存する処理」のことです。
手作業とVBAで、どれくらい差が出るのか比べてみましょう。
| 作業内容 | 手作業 | VBA |
|---|---|---|
| 1ファイルの取り込み | 約2〜3分 | 1秒以下 |
| 10ファイルの取り込み | 約30分 | 数秒 |
| 貼り付け位置のミス | 起きやすい | 起きない |
ポイントは、ファイル数が増えるほど効果が大きくなることです。フォルダの中のCSVを全部まとめて処理する、といった芸当もマクロなら簡単にできます。
CSVを扱う方法は大きく2つあります。1つは昔からある「Open文」、もう1つは「FileSystemObject(エフエスオー)」です。まずは両方の基本を押さえて、後半で使い分けを解説します。
CSVファイルの中身はただのテキスト
CSVは「Comma Separated Values」の略で、カンマで区切られたテキストファイルです。Excelで開くと表のように見えますが、中身はメモ帳で開けるただの文字列です。
氏名,部署,売上
田中,営業1課,150000
佐藤,営業2課,98000
このように、1行が1レコード、カンマが列の区切りになっています。VBAでは、この「1行ずつ読む」「カンマで分ける」という流れでデータを扱います。
VBEの起動とコードの準備
CSV処理のコードを書く前に、VBA専用のエディタ「VBE(Visual Basic Editor)」を開きます。ここがマクロを書く作業場所です。
VBE(Visual Basic Editor)の開き方
VBEを開く方法は2つあります。
- キーボードで
Alt + F11を押す(一番手軽です) - リボンの「開発」タブ →「Visual Basic」をクリックする
「開発」タブが見当たらない場合は、次の手順で表示できます。
- 「ファイル」→「オプション」を開く
- 「リボンのユーザー設定」を選ぶ
- 右側の一覧で「開発」にチェックを入れる
- 「OK」を押す
これでリボンに「開発」タブが追加されます。
標準モジュールの挿入
VBEが開いたら、コードを書く場所「標準モジュール」を追加します。
- メニューの「挿入」→「標準モジュール」をクリックする
- 画面に白いコード入力エリアが表示される
この白い画面に、これから紹介するコードを貼り付けて使います。準備はこれだけです。
基本コード|Open文でCSVを読み込む
まずは一番シンプルな方法、Open文でCSVを読み込むコードです。下のコードをそのままコピペすれば動きます。
Sub CSV読み込み_Open()
Dim sFilePath As String '読み込むCSVのパス
Dim sLine As String '1行分の文字列
Dim vData As Variant 'カンマで分割した配列
Dim iRow As Long '書き込む行番号
sFilePath = "C:datasample.csv" 'CSVのパスを指定
iRow = 1 '1行目から書き込む
Open sFilePath For Input As #1 'ファイルを読み込みモードで開く
Do Until EOF(1) 'ファイルの末尾まで繰り返す
Line Input #1, sLine '1行を読み込む
vData = Split(sLine, ",") 'カンマで分割する
'--- 分割した値をセルに書き込む ---
Dim iCol As Long '列番号
For iCol = 0 To UBound(vData)
Cells(iRow, iCol + 1).Value = vData(iCol)
Next iCol
iRow = iRow + 1 '次の行へ
Loop
Close #1 'ファイルを閉じる
MsgBox "読み込みが完了しました" '完了メッセージ
End Sub
sFilePath の部分を、自分のCSVファイルのパスに書き換えてください。実行すると、アクティブなシートの1行目からデータが展開されます。
実行方法は2通りです。VBE上で F5 キーを押すか、Excelに戻って「開発」タブ →「マクロ」から CSV読み込み_Open を選んで実行します。
コードの仕組みを理解する
このコードがやっていることを、順番に見ていきましょう。難しく見えますが、流れはとてもシンプルです。
Open sFilePath For Input As #1でCSVを読み込み用に開くDo Until EOF(1)でファイルの最後まで1行ずつ処理するLine Input #1, sLineで1行を文字列として読み込むSplit(sLine, ",")でカンマごとに分けて配列にするCells(iRow, iCol + 1)で各セルに書き込むClose #1でファイルを閉じる
#1 は「ファイル番号」と呼ばれる目印です。複数ファイルを同時に開くときは #2、#3 と番号を変えます。EOF は「End Of File」の略で、ファイルの終わりを意味します。
基本コード|CSVを書き出す
次は逆方向、シートのデータをCSVファイルとして書き出すコードです。集計結果を他システムに渡したいときに役立ちます。
Sub CSV書き出し_Open()
Dim sFilePath As String '書き出すCSVのパス
Dim iLastRow As Long '最終行
Dim iLastCol As Long '最終列
Dim iRow As Long '行カウンター
Dim iCol As Long '列カウンター
Dim sLine As String '1行分の文字列
sFilePath = "C:dataoutput.csv" '保存先のパスを指定
iLastRow = Cells(Rows.Count, 1).End(xlUp).Row '最終行を取得
iLastCol = Cells(1, Columns.Count).End(xlToLeft).Column '最終列を取得
Open sFilePath For Output As #1 'ファイルを書き込みモードで開く
For iRow = 1 To iLastRow '1行目から最終行まで
sLine = "" '行の文字列を初期化
For iCol = 1 To iLastCol '1列目から最終列まで
sLine = sLine & Cells(iRow, iCol).Value 'セルの値を連結
If iCol < iLastCol Then sLine = sLine & "," '区切りのカンマを追加
Next iCol
Print #1, sLine '1行をファイルに書き出す
Next iRow
Close #1 'ファイルを閉じる
MsgBox "書き出しが完了しました" '完了メッセージ
End Sub
このコードは、シートの使われている範囲を自動で判定してCSVに出力します。iLastRow と iLastCol で、データがどこまで入っているかを取得しているのがポイントです。
最終行の取得については、Excel VBAで最終行を取得する方法でくわしく解説しています。データ範囲を正しく取れないと書き出しが途中で切れるので、あわせて確認しておくと安心です。
Print #1, sLine で1行ずつファイルに書き込みます。最後のカンマが余計に付かないよう、If iCol < iLastCol Then で制御しているところも実務では大事です。
FileSystemObjectでCSVを扱う方法
Open文と並んでよく使われるのが、FileSystemObject(FSO)です。FSOは、ファイルやフォルダを扱うための専用オブジェクトで、コードが読みやすくなるのが特長です。
FSOを使うには2つの書き方があります。1つは事前バインディング(参照設定が必要)、もう1つは遅延バインディング(参照設定が不要)です。配布しやすいのは、参照設定がいらない遅延バインディングです。
Sub CSV読み込み_FSO()
Dim oFSO As Object 'FileSystemObject
Dim oStream As Object 'テキストストリーム
Dim sLine As String '1行分の文字列
Dim vData As Variant 'カンマで分割した配列
Dim iRow As Long '書き込む行番号
Dim iCol As Long '列番号
Set oFSO = CreateObject("Scripting.FileSystemObject") 'FSOを生成
Set oStream = oFSO.OpenTextFile("C:datasample.csv", 1) '読み込みモードで開く
iRow = 1 '1行目から書き込む
Do Until oStream.AtEndOfStream 'ファイルの末尾まで繰り返す
sLine = oStream.ReadLine '1行を読み込む
vData = Split(sLine, ",") 'カンマで分割する
'--- 分割した値をセルに書き込む ---
For iCol = 0 To UBound(vData)
Cells(iRow, iCol + 1).Value = vData(iCol)
Next iCol
iRow = iRow + 1 '次の行へ
Loop
oStream.Close 'ストリームを閉じる
Set oStream = Nothing 'オブジェクトを解放
Set oFSO = Nothing 'オブジェクトを解放
MsgBox "読み込みが完了しました" '完了メッセージ
End Sub
OpenTextFile の第2引数 1 が「読み込みモード」を表します。書き出すときは 2(上書き)または 8(追記)を使います。処理の流れはOpen文とほぼ同じで、1行ずつ読んでカンマで分割しています。
Open文とFileSystemObjectの使い分け
ここがこの記事の核心です。どちらを使うべきか、判断基準を表にまとめました。
| 比較項目 | Open文 | FileSystemObject |
|---|---|---|
| 書き方 | VBA標準(追加設定不要) | オブジェクト経由 |
| コードの読みやすさ | やや古風 | 直感的でわかりやすい |
| フォルダ操作 | 苦手 | 得意(一覧取得が簡単) |
| 処理速度 | やや速い | 標準 |
| 文字コード | Shift-JIS中心 | UTF-8も扱いやすい |
ざっくりした使い分けはこうです。1ファイルだけ素早く処理するならOpen文が向いています。フォルダ内の一覧を扱ったり複数ファイルをまとめて処理するならFSOが便利です。
迷ったらFSOを選んでおけば、後からフォルダ処理に発展させるときに楽です。次の応用編でその威力がわかります。
実践コード|フォルダ内のCSVを全件一括処理する
ここからが本番です。「毎日届くCSVが溜まっているフォルダを、まとめて1枚のシートに統合したい」という実務ニーズに応えるコードを紹介します。FSOのフォルダ操作が活躍する場面です。
Sub CSV一括取り込み()
Dim oFSO As Object 'FileSystemObject
Dim oFolder As Object '対象フォルダ
Dim oFile As Object '個々のファイル
Dim oStream As Object 'テキストストリーム
Dim sFolderPath As String '対象フォルダのパス
Dim sLine As String '1行分の文字列
Dim vData As Variant 'カンマで分割した配列
Dim iRow As Long '書き込む行番号
Dim iCol As Long '列番号
sFolderPath = "C:datacsv" '対象フォルダを指定
iRow = 1 '1行目から書き込む
Set oFSO = CreateObject("Scripting.FileSystemObject") 'FSOを生成
Set oFolder = oFSO.GetFolder(sFolderPath) 'フォルダを取得
'--- フォルダ内のファイルを1つずつ処理 ---
For Each oFile In oFolder.Files
'--- 拡張子がcsvのファイルだけ対象にする ---
If LCase(oFSO.GetExtensionName(oFile.Name)) = "csv" Then
Set oStream = oFSO.OpenTextFile(oFile.Path, 1) '読み込みモードで開く
Do Until oStream.AtEndOfStream '末尾まで繰り返す
sLine = oStream.ReadLine '1行を読み込む
vData = Split(sLine, ",") 'カンマで分割する
For iCol = 0 To UBound(vData)
Cells(iRow, iCol + 1).Value = vData(iCol)
Next iCol
iRow = iRow + 1 '次の行へ
Loop
oStream.Close 'ストリームを閉じる
End If
Next oFile
Set oStream = Nothing 'オブジェクトを解放
Set oFolder = Nothing 'オブジェクトを解放
Set oFSO = Nothing 'オブジェクトを解放
MsgBox "フォルダ内のCSVをすべて取り込みました" '完了メッセージ
End Sub
このコードのキモは For Each oFile In oFolder.Files の部分です。フォルダの中のファイルを1つずつ取り出して、CSVだけを順番に取り込んでいます。For Each の使い方はExcel VBAでFor Each Nextを使う方法でくわしく解説しています。
GetExtensionName で拡張子を調べ、csv のファイルだけ処理するようにしています。これでフォルダにExcelファイルやテキストファイルが混ざっていても安全です。
変更すべき箇所は sFolderPath の1行だけです。自分のCSVが入っているフォルダのパスに書き換えてください。末尾の「」を忘れないのがポイントです。
1行目のヘッダーをスキップしたいとき
複数ファイルを統合すると、各CSVの見出し行(ヘッダー)が何度も繰り返されてしまいます。これを防ぐには、各ファイルの1行目を読み飛ばす処理を追加します。
Dim isFirstLine As Boolean '1行目かどうかの判定
isFirstLine = True 'ファイルごとにTrueにリセット
Do Until oStream.AtEndOfStream
sLine = oStream.ReadLine '1行を読み込む
'--- 1行目(ヘッダー)はスキップする ---
If isFirstLine Then
isFirstLine = False
Else
vData = Split(sLine, ",")
For iCol = 0 To UBound(vData)
Cells(iRow, iCol + 1).Value = vData(iCol)
Next iCol
iRow = iRow + 1
End If
Loop
isFirstLine というフラグを使って、ファイルの最初の1行だけ書き込みをスキップしています。ファイルごとに True へ戻すのを忘れないようにしてください。
文字コードのトラブル対処(Shift-JIS/UTF-8)
CSV処理でつまずきやすいのが、文字化けです。CSVには主に「Shift-JIS」と「UTF-8」という2つの文字コードがあります。これが合っていないと、日本語が「譁・喧縺・」のように崩れてしまいます。
Open文や OpenTextFile は、基本的にShift-JISとして読み込みます。最近の業務システムはUTF-8で出力することが多いので、ここで文字化けが起きやすいのです。
UTF-8のCSVを正しく読むには、ADODB.Streamというオブジェクトを使います。文字コードを指定して読み込めるのが利点です。
Sub UTF8のCSV読み込み()
Dim oStream As Object 'ADODB.Stream
Dim sText As String '読み込んだ全文
Dim vLines As Variant '行ごとの配列
Dim vData As Variant 'カンマで分割した配列
Dim iRow As Long '書き込む行番号
Dim iCol As Long '列番号
Dim i As Long '行ループ用
Set oStream = CreateObject("ADODB.Stream") 'ストリームを生成
oStream.Charset = "UTF-8" '文字コードをUTF-8に指定
oStream.Open 'ストリームを開く
oStream.LoadFromFile "C:datautf8.csv" 'ファイルを読み込む
sText = oStream.ReadText '全文をテキストとして取得
oStream.Close 'ストリームを閉じる
Set oStream = Nothing 'オブジェクトを解放
vLines = Split(sText, vbCrLf) '改行で行に分割
iRow = 1 '1行目から書き込む
For i = 0 To UBound(vLines)
If vLines(i) <> "" Then '空行はスキップ
vData = Split(vLines(i), ",") 'カンマで分割
For iCol = 0 To UBound(vData)
Cells(iRow, iCol + 1).Value = vData(iCol)
Next iCol
iRow = iRow + 1 '次の行へ
End If
Next i
MsgBox "UTF-8のCSVを読み込みました" '完了メッセージ
End Sub
oStream.Charset = "UTF-8" の1行で文字コードを指定するのがポイントです。Shift-JISのファイルなら "Shift_JIS" に変えれば対応できます。
文字化けの原因と対処を体系的に知りたい方は、ExcelでCSVが文字化けする原因と直し方もどうぞ。手作業での開き方も含めて整理しています。
よくあるエラーと対処法
CSV処理でよく出るエラーと、その対処法をまとめました。エラーメッセージが出ても、原因がわかれば落ち着いて対応できます。
| エラー・症状 | 主な原因 | 対処法 |
|---|---|---|
| 実行時エラー'53' ファイルが見つかりません | パスやファイル名の間違い | パスを正確に指定し直す |
| 実行時エラー'76' パスが見つかりません | フォルダが存在しない | フォルダのパスを確認する |
| 実行時エラー'70' 書き込みできません | ファイルを別ソフトで開いている | Excelやメモ帳を閉じる |
| 日本語が文字化けする | 文字コードの不一致 | ADODB.Streamで文字コード指定 |
| データが1列に詰まる | 区切り文字がカンマでない | Splitの第2引数を見直す |
特に多いのが、ファイルを開いたまま書き出そうとして起きる「実行時エラー'70'」です。出力先のCSVをExcelやメモ帳で開いていないか、まず確認してください。
実務で使うなら、エラーが出ても処理が止まらないようにエラーハンドリングを入れておくと安心です。On Error GoTo の使い方はVBAのエラーハンドリング完全ガイドでくわしく解説しています。
マクロが無効になっていないか確認する
書いたマクロが動かないときは、ファイルの保存形式やセキュリティ設定が原因かもしれません。次の2点を確認してください。
- ファイルを「Excelマクロ有効ブック(.xlsm)」で保存しているか
- マクロのセキュリティ設定でマクロが許可されているか
通常の .xlsx 形式で保存すると、マクロが消えてしまいます。マクロを含むファイルは必ず .xlsm で保存しましょう。これはCSV処理に限らず、すべてのVBA作業で共通の注意点です。
まとめ
VBAを使えば、手作業で繰り返していたCSVの取り込みと書き出しを、ボタン1つで自動化できます。最後にポイントを整理しておきます。
- 読み込みの基本:
Open ~ For Inputまたは FSOのOpenTextFileで1行ずつ読む - 書き出しの基本:
Open ~ For OutputでPrint #1を使って1行ずつ書く - 使い分け: 1ファイルならOpen文、フォルダ一括処理ならFileSystemObject
- 一括処理:
For Each oFile In oFolder.Filesでフォルダ内のCSVを全件処理 - 文字化け対処: UTF-8のCSVはADODB.Streamで文字コードを指定して読む
- 保存形式: マクロを含むファイルは必ず
.xlsmで保存する
毎月のCSV取り込みに30分かかっていた作業も、自動化すれば数秒で終わります。初回のコード作成だけがんばれば、あとはずっと時短の恩恵を受けられます。まずはこの記事の基本コードをコピペして、sFilePath を自分のファイルに書き換えるところから試してみてください。
VBAの基本構文をテーマ別に学び直したい方は、こちらの記事もあわせてどうぞ。
- 繰り返し処理の基本はExcel VBAでFor文を使う方法
- コレクション処理はExcel VBAでFor Each Nextを使う方法
- セル操作の基本はExcel VBAでRangeを使う方法
- 最終行取得はExcel VBAで最終行を取得する方法
VBA全体を体系的に学びたい方もいるでしょう。入門ハブ記事のExcel VBAでマクロ自動化を始めるための完全ガイドも参考にしてください。
