【VBA】UTF-8でテキストファイルを読み書きする方法
更新日:2023/12/20
UTF-8で書き込まれたテキストファイルを、VBAのOpenメソッドで操作すると文字化けします。
外部から持ち込まれたファイルはUTF-8のケースが多いので困るケースがあります。
そこで今回は、UTF-8ファイルを読み書きする方法をお伝えします
UTF-8は文字化けする
VBAは内部的にUTF-16(Unicode)が使用されています。
一方、VBエディタはシフトJISで内容が記憶されます。
整合性を取るために、実行時にコードがUTF-16に変換されます。
同様にOpenステートメントで開かれたテキストファイルは、読み込み時にシフトJISからUTF-16に変換され、書き込み時はUTF-16からシフトJISに変換されます。
このようにOpenステートメントは文字コードがシフトJISという前提で動作しています。
そのため、他の文字コード、例えばUTF-8を読み込むと変換に失敗して文字化けします。
そこで読み書きの際に、UTF-8からUTF-16への変換、またはその逆変換を行ってくれるライブラリを使用することで、UTF-8でテキストファイルを読み書きすることが可能となります。
その手段として今回は、Microsoft ActiveX Data Objects Library(ADODB)のStreamオブジェクトを使用します。
操作イメージ
Streamオブジェクトは、内容を記憶しておくバッファを持っています。
Streamオブジェクトのファイル読み込みメソッドを実行すると、このバッファにファイルの内容が保存されます。
このときファイルの文字形式がUTF-8指定されていると、UTF-8からUTF-16へ変換されます。
その後、Streamオブジェクトの読み込みメソッドを実行すると、バッファからデータを取り出します。
取り出しは一度にまとめてでも、数回に分けてでも、どちらでも可能です。
ファイルへの書き込みは、書き込みメソッドでバッファに書き込みます。
書き込みは数回に分けることも可能です。
その後、ファイル書き込みメソッドを実行すると、バッファの内容がファイルに書き込まれます。
このときファイルの文字形式がUTF-8指定されていると、UTF-16からUTF-8へ変換されます。
ADODB.Streamオブジェクトの取得
UTF-8ファイルを読み書きするには、まずはADODB.Streamオブジェクトを取得する必要があります。
ADODB.Streamオブジェクトの取得方法は二つあります。
一つは、文字列"ADODB.Stream"をCreateObject関数に渡す方法です。
Dim fso As Object
Set fso = CreateObject("ADODB.Stream")
もう一つはVBエディタのメニュー:ツールから参照設定画面を開いて『Microsoft ActiveX Data Objects XX.X Library』を参照設定してから次のコードを実行する方法です。
※XX.Xは数値です。複数あるので一番値が大きいものを選択します。
Dim adoStream As New ADODB.Stream
参照設定をおこなうと、コード入力時にメソッド名候補が表示されます。
入力ミスを防げるので便利です。
UTF-8ファイルの読み込み
ADODB.StreamオブジェクトでのUTF-8ファイル読み込は、一度に全ての内容を処理する方法と、一行ずつ処理する方法の二つあります。
その二つの方法について解説します。
全て読み込み
UTF-8ファイルの全ての内容を変数に読み込むときは、次のような流れでコードを記述します。
With ADODB.Streamオブジェクト .Open .Type = adTypeText .Charset = "UTF-8" .LoadFromFile ファイルのパス 変数 = .ReadText .Close End With
まずは、Openメソッドでストリームを開きます。
次に、テキストかバイナリかをTypeプロパティで指定します。
設定できる値はStreamTypeEnum型です。
Charsetプロパティは、テキストファイルの文字セットを文字列で指定します。
このプロパティは、TypeプロパティがadTypeTextの時のみ有効です。
LoadFromFileメソッドは、既存ファイルの内容を読み込みます。
ファイルが存在しない場合はエラーです。
ReadTextメソッドは引数として取り出すバイト数を受け取り、そのバイト数だけ読み込んだデータを返します。
またはStreamReadEnum型を受け取り、全てのデータまたは行単位でデータを返します。
引数が省略されると、全てのデータを返します。
最後にCloseメソッドで、ストリームを閉じます。
Sub readTextTest1()
Const fileName As String = "C:\Users\xxx\Documents\text.txt"
Dim adoStream As New ADODB.Stream
Dim textData As String
With adoStream
.Open
.Type = adTypeText
.Charset = "UTF-8"
.LoadFromFile fileName
textData = .ReadText
.Close
End With
Debug.Print textData
End Sub
1行ずつ読み込み
UTF-8ファイルの内容を1行ずつ変数に読み込むときは、次のような流れでコードを記述します。
With ADODB.Streamオブジェクト .Open .Type = adTypeText .Charset = "UTF-8" .LineSeparator = 改行種類 .LoadFromFile ファイルのパス Do Until .EOS 変数 = .ReadText(adReadLine) Loop .Close End With
全て読み込みのケースとほぼ同じです。
異なるのはLineSeparatorプロパティで改行の種類を指定している点です。
LineSeparatorプロパティは、LineSeparatorsEnum型の値を指定します。
実際のファイルの改行コードと一致しない場合、全ての行を一度に読み取ったり、CRまたはLFが読み取ったデータに含まれる等の不具合が生じます。
改行コードが不明なときは、全て読み込み後にReplaceで改行コードを統一してSplitで分割するか、一文字単位で改行を確認しながら読み込むなどの工夫が必要です。
EOSプロパティは、現在位置がストリームの終端まで達するとTrueを返します。
そのため、ReadTextメソッドで1行読み込み、EOSプロパティがTrueを返すまでループします。
Sub readTextTest2()
Const fileName As String = "C:\Users\xxx\Documents\text.txt"
Dim adoStream As New ADODB.Stream
With adoStream
.Open
.Type = adTypeText
.Charset = "UTF-8"
.LineSeparator = adCRLF
.LoadFromFile fileName
Do Until .EOS
Debug.Print .ReadText(adReadLine)
Loop
.Close
End With
End Sub
UTF-8ファイルの書き込み
ADODB.StreamオブジェクトでのUTF-8ファイル書き込みは、その都度書き込む方法と、一行ずつ書き込む方法、追記で書き込む方法の二つあります。
その二つの方法について解説します。
その都度書き込む
UTF-8ファイルに文字をその都度書き込むときは、次のような流れでコードを記述します。
With ADODB.Streamオブジェクト .Open .Type = adTypeText .Charset = "UTF-8" .WriteText 文字列 ・・・任意の回数書き込み .SaveToFile ファイルのパス, adSaveCreateOverWrite .Close End With
ストリームを開いた後、Typeプロパティでテキストモード(StreamTypeEnum型)に、Charsetプロパティにテキストファイルの文字コードを指定します。
WriteTextメソッドにファイルに書き込む文字列を渡します。
これは、任意の回数に分けて実行できます。
SaveToFileメソッドでファイルに書き込みます。
その際、二つ目の引数で上書きするかどうかを指定できます。
指定する値はSaveOptionsEnum型から一つです。
出力先のファイルは、VBAと関連付けられません。
出力後の他アプリで変更や削除を行えます。
最後にCloseメソッドで、ストリームを閉じます。
Sub writeTextTest1()
Const fileName As String = "C:\Users\xxx\Documents\text.txt"
Dim adoStream As New ADODB.Stream
With adoStream
.Open
.Type = adTypeText
.Charset = "UTF-8"
.WriteText "こんにちは"
.WriteText "よろしくおねがいします"
.SaveToFile fileName, adSaveCreateNotExist
.Close
End With
Call readTextTest1
End Sub
最後のreadTextTest1は、全て読み込みで紹介しているコードです。
上のコードを実行すると、イミディエイトウィンドウに次のような文字列が表示されます。
こんにちはよろしくおねがいします
一行ずつ書き込む
UTF-8ファイルに文字を一行ずつ書き込むときは、次のような流れでコードを記述します。
With ADODB.Streamオブジェクト .Open .Type = adTypeText .Charset = "UTF-8" .LineSeparator = 改行コード .WriteText 文字列 , adWriteLine ・・・任意の回数書き込み .SaveToFile ファイルのパス, adSaveCreateOverWrite .Close End With
その都度書き込むのケースとほぼ同じです。
相違点はLineSeparatorプロパティで改行で使用するコードを指定している点です。
LineSeparatorプロパティは、LineSeparatorsEnum型の値を指定します。
またWriteTextメソッドで書き込むとき、第二引数にadWriteLine(SaveOptionsEnum型)を指定します。
これにより文字列を書き込み後に、LineSeparatorプロパティで指定した改行コードが書き込まれます。
Sub writeTextTest2()
Const fileName As String = "C:\Users\xxx\Documents\text.txt"
Dim adoStream As New ADODB.Stream
With adoStream
.Open
.Type = adTypeText
.Charset = "UTF-8"
.LineSeparator = adCRLF
.WriteText "こんにちは", adWriteLine
.WriteText "よろしくおねがいします", adWriteLine
.SaveToFile fileName, adSaveCreateNotExist
.Close
End With
Call readTextTest1
End Sub
最後のreadTextTest1は、全て読み込みで紹介しているコードです。
上のコードを実行すると、イミディエイトウィンドウに次のような文字列が表示されます。
こんにちは よろしくおねがいします
追記で書き込む方法
UTF-8ファイルに追記書き込みするときは、次のような流れでコードを記述します。
With ADODB.Streamオブジェクト .Open .Type = adTypeText .Charset = "UTF-8" .LoadFromFile ファイルのパス .Position = .size .WriteText 文字列 ・・・任意の回数書き込み .SaveToFile ファイルのパス, adSaveCreateOverWrite .Close End With
全て読み込みで紹介した方法でファイルを読み込んだ後、現在位置をストリームの末尾に移動します。
次に、その都度書き込むで紹介した方法でファイルに書き込みます。
1行単位で書き込むときは、一行ずつ書き込むを参考にしてください。
Streamオブジェクトにはストリームの末尾に移動するSetEOSメソッドがありますが、ここでは上手く動作しません。
そのため、現在位置のストリーム末尾への移動は、Positionプロパティにバッファのサイズをセットしています。
Sub writeAddTextTest1()
Const fileName As String = "C:\Users\xxx\Documents\text.txt"
Dim adoStream As New ADODB.Stream
Debug.Print "【追記前】"
Call readTextTest1
With adoStream
.Open
.Type = adTypeText
.Charset = "UTF-8"
.LineSeparator = adCRLF
.Position = .size
.WriteText vbCrLf & "よろしくお願いします!"
.SaveToFile fileName, adSaveCreateNotExist
.Close
End With
Debug.Print "【追記後】"
Call readTextTest1
End Sub
最後のreadTextTest1は、全て読み込みで紹介しているコードです。
上のコードを実行すると、イミディエイトウィンドウに次のような文字列が表示されます。
【追記前】 こんにちは! 【追記後】 こんにちは! よろしくお願いします!
補足:関連する型定義
このページで使用されている型の定数と値を紹介します。
StreamTypeEnum型
StreamTypeEnum型は、Typeプロパティで使用される列挙型です。
定数 | 値 | 意味 |
---|---|---|
adTypeBinary | 1 | バイナリファイル |
adTypeText | 2 | テキストファイル |
StreamReadEnum型
StreamReadEnum型は、ReadTextメソッド等で使用される列挙型です。
定数 | 値 | 意味 |
---|---|---|
adReadAll | -1 | 全て読み込む |
adReadLine | -2 | 1行読み込む |
LineSeparatorsEnum 型
LineSeparatorsEnum 型は、LineSeparatorプロパティで使用される列挙型です。
定数 | 値 | 意味 |
---|---|---|
adCRLF | -1 | 改行コードはCRLF |
adLF | 10 | 改行コードはLF |
adCR | 13 | 改行コードはCR |
SaveOptionsEnum型
SaveOptionsEnum型は、SaveToFileメソッドで使用される列挙型です。
定数 | 値 | 既存ファイルの状況 | ||
---|---|---|---|---|
存在しない | 存在する | 読込専用 | ||
adSaveCreateNotExist | 1 | 作成する | エラー | エラー |
adSaveCreateOverWrite | 2 | 作成する | 上書きする | エラー |
更新日:2023/12/20
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。