「VBAでCSVファイルを読み込んだら日本語が文字化けした」という経験がある方は多いのではないでしょうか。原因の多くは、ファイルの文字コード(UTF-8・Shift-JISなど)とVBA側の読み込み方法が合っていないことにあります。
この記事では、Open ステートメントで文字化けが起きる理由から、ADODB.Streamオブジェクトを使ってUTF-8のファイルを正しく読み書きする方法まで、実際に使えるコードで解説します。
なぜ文字化けが起きるのか
VBAのOpenステートメントを使った読み込みは、内部的にOSの標準文字コード(日本語Windowsでは基本的にShift-JIS)を前提としています。そのため、メモ帳などで「UTF-8」形式で保存されたCSVファイルをOpenで読み込むと、日本語部分が正しく解釈されず文字化けが発生します。
Sub 文字化けする例()
Dim buf As String
Open ThisWorkbook.Path & "\data_utf8.csv" For Input As #1
Do Until EOF(1)
Line Input #1, buf
Debug.Print buf ' UTF-8ファイルだと日本語が文字化けする
Loop
Close #1
End Sub
近年はWebサービスからダウンロードするCSVがUTF-8であることが多く、この問題に遭遇しやすくなっています。解決にはADODB.Streamオブジェクトを使うのが確実です。
ADODB.StreamでUTF-8ファイルを読み込む
ADODB.Streamは文字コードを明示的に指定して読み書きできるオブジェクトです。参照設定は不要で、CreateObjectから呼び出せます。
Sub UTF8ファイルを読み込む()
Dim stream As Object
Dim allText As String
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2 ' テキストモード
stream.Charset = "UTF-8"
stream.Open
stream.LoadFromFile ThisWorkbook.Path & "\data_utf8.csv"
allText = stream.ReadText
stream.Close
Set stream = Nothing
Debug.Print allText ' 文字化けせずに表示される
End Sub
Charsetプロパティに"UTF-8"を指定して開くのがポイントです。読み込んだallTextをSplit関数で改行ごとに分割すれば、1行ずつ処理することもできます。
Sub UTF8ファイルを1行ずつ処理する()
Dim stream As Object
Dim allText As String
Dim lines() As String
Dim i As Long
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2
stream.Charset = "UTF-8"
stream.Open
stream.LoadFromFile ThisWorkbook.Path & "\data_utf8.csv"
allText = stream.ReadText
stream.Close
Set stream = Nothing
lines = Split(allText, vbLf)
For i = LBound(lines) To UBound(lines)
If Trim(lines(i)) <> "" Then
Debug.Print i & "行目: " & lines(i)
End If
Next i
End Sub
改行コードがファイルによってvbCrLfだったりvbLfだったりするため、Replace関数でvbCrLfをvbLfに統一してからSplitすると、行がずれるトラブルを防げます。
BOMあり・BOMなしUTF-8の違いに注意する
UTF-8には、ファイル先頭に「BOM(Byte Order Mark)」と呼ばれる目印が付いているものと付いていないものがあります。ADODB.StreamのCharset = "UTF-8"はBOMありのファイルを想定しているため、BOMなしのUTF-8ファイルを読み込むと、先頭に余分な文字が混入することがあります。
先頭1文字にChr(65279)(BOM)が含まれていないか確認し、あれば取り除くコードを入れておくと安全です。
Function BOM除去(ByVal text As String) As String
If Len(text) > 0 Then
If AscW(Left(text, 1)) = 65279 Then
text = Mid(text, 2)
End If
End If
BOM除去 = text
End Function
allTextをSplitする前にallText = BOM除去(allText)のように呼び出しておけば、先頭行のデータが余計な文字で汚れるのを防げます。
UTF-8形式でファイルを書き出す
逆に、VBAからUTF-8形式でファイルを書き出したい場合もADODB.Streamが使えます。他システムに渡すCSVなど、文字コード指定が必要な場面で役立ちます。
Sub UTF8ファイルを書き出す()
Dim stream As Object
Dim outputText As String
outputText = "名前,部署" & vbCrLf & "山田太郎,営業部" & vbCrLf & "鈴木花子,経理部"
Set stream = CreateObject("ADODB.Stream")
stream.Type = 2
stream.Charset = "UTF-8"
stream.Open
stream.WriteText outputText
stream.SaveToFile ThisWorkbook.Path & "\output_utf8.csv", 2 ' 2 = 上書き保存
stream.Close
Set stream = Nothing
MsgBox "UTF-8形式で保存しました。"
End Sub
SaveToFileの第2引数に2(adSaveCreateOverWrite)を指定すると、同名ファイルがあっても上書き保存されます。なお、この方法で保存するとBOM付きUTF-8になります。BOMなしで保存したい場合は、一度Shift-JISで書き出してからバイナリ操作でBOM部分を取り除くなど、別途工夫が必要です。
まとめ
VBAで文字化けが起きたときは、まずファイルの文字コードを確認し、OpenステートメントではなくADODB.Streamを使う方法に切り替えるのが有効です。
OpenステートメントはOS標準(Shift-JIS)を前提としており、UTF-8ファイルは文字化けしやすいADODB.StreamのCharsetプロパティで文字コードを明示的に指定できる- BOMあり・BOMなしの違いに注意し、必要ならBOM除去処理を入れる
- 書き出し時も同様に
Charsetを指定すれば、UTF-8形式で保存できる
CSVを扱うマクロを作る際は、まず対象ファイルの文字コードを確認する習慣をつけておくと、文字化けトラブルを未然に防げます。


コメント