小さい頃はエラ呼吸

いつのまにやら肺で呼吸をしています。


ADODB.Streamオブジェクトを利用したUTF-8ファイルの読み書き

はじめに

VBScriptでファイルを扱う場合、通常はFileSystemObjectを利用します。しかしながら、FileSystemObjectはShift_JISあるいはUTF-16形式で保存されたファイルしか扱えません。このため、VBScriptでUTF-8のファイルを扱うにはADODB.Streamオブジェクトを利用します。

CreateTextFileの第3引数をtrueにするとUTF-16でファイルを作る。falseにするとShift_JIS。UTF-8で作ることはできない。UTF-8で作りたいときはFileSystemObjectではなくADODB.Streamを使う。
FileSystemObjectの使い方まとめ - 今日覚えたこと


最速攻略 VBScriptサンプル大全集 Windows7/Vista/XP/2000対応
結城 圭介
技術評論社
売り上げランキング: 270,148

ADODB.Streamオブジェクトを利用してファイルの読み込む

ファイル読み込み用のクラスを作成する
Option Explicit
Class UTF8FileReader
  Private name, errNo, errDesc
  
  ' コンストラクタ
  Private Sub Class_Initialize
    name = "UTF8FileReader"
  End Sub
  
  ' ファイルの中身を戻り値として返す
  Public Function ReadAll(fileName)
    On Error Resume Next
    Dim medthodName : medthodName = name & "." & "ReadAll"
    
    With CreateObject("ADODB.Stream")
      .Charset = "UTF-8"
      .Open
      .LoadFromFile(fileName)
      ReadAll = .ReadText
      .Close
    End With
    If Err.Number <> 0 Then
      errNo = Err.Number
      errDesc = Err.Description
      On Error GoTo 0
      Call Err.Raise(errNo, medthodName, errDesc)
    End If
    
  End Function
  
  ' ファイルを1行ずつ読み込み、配列に格納して返す
  Public Function ReadByLine(fileName)
    On Error Resume Next
    Dim medthodName : medthodName = name & "." & "ReadByLine"
    Dim arrRet()
    ReDim Preserve arrRet(0)
    
    With CreateObject("ADODB.Stream")
      .Charset = "UTF-8"
      .Open
      .LoadFromFile(fileName)
      Do While Not .EOS
        arrRet(UBound(arrRet)) = .ReadText(-2)
        ReDim Preserve arrRet(UBound(arrRet) + 1)
      Loop
      .Close
    End With
    If Err.Number <> 0 Then
      errNo = Err.Number
      errDesc = Err.Description
      On Error GoTo 0
      Call Err.Raise(errNo, medthodName, errDesc)
    End If
    ReadByLine = arrRet
    
  End Function
  
End Class
ファイルをすべて読み込む場合
Set fr = New UTF8FileReader
WScript.Echo fr.ReadAll("xxx.txt")
If Err.Number <> 0 Then
  ' エラー処理
End If
1行ずつ読み込み、配列に格納する場合
Set fr = New UTF8FileReader
arrText = fr.ReadByLine("xxx.txt")
If Err.Number <> 0 Then
  ' エラー処理
End If

ADODB.Streamオブジェクトを利用してファイルへ書きこむ

ファイル書き込み用のクラスを作成する
Option Explicit
Class UTF8FileWriter
  Private name, errNo, errDesc
  
  ' コンストラクタ
  Private Sub Class_Initialize
    name = "UTF8FileWriter"
  End Sub
  
  ' 引数で指定された値をファイルに書き込む
  Public Sub WriteAll(text, fileName)
    On Error Resume Next
    Dim medthodName : medthodName = name & "." & "WriteAll"
    
    With CreateObject("ADODB.Stream")
      .Type = 2
      .charset = "UTF-8"
      .Open
      .writeText text
      .saveToFile fileName, 2
      .Close
    End With
    If Err.Number <> 0 Then
      errNo = Err.Number
      errDesc = Err.Description
      On Error GoTo 0
      Call Err.Raise(errNo, medthodName, errDesc)
    End If
    
  End Sub
  
  ' 配列の中身を1行ずつファイルに書き込む
  Public Sub WriteByLine(arrText, fileName)
    On Error Resume Next
    Dim medthodName : medthodName = name & "." & "WriteByLine"
    
    With CreateObject("ADODB.Stream")
      .Type = 2
      .charset = "UTF-8"
      .Open
      Dim tmp
      For Each tmp In arrText
        .writeText tmp, 1
      Next
      .saveToFile fileName, 2
      .Close
    End With
    If Err.Number <> 0 Then
      errNo = Err.Number
      errDesc = Err.Description
      On Error GoTo 0
      Call Err.Raise(errNo, medthodName, errDesc)
    End If
    
  End Sub
  
End Class
ファイルに一括で書き込む場合
Call fw.WriteAll("ほげ", "yyy.txt")
If Err.Number <> 0 Then
  ' エラー処理
End If
配列の中身を1行ずつ書き込む場合
Call fw.WriteByLine(Array("あ","い","う"), "yyy.txt")
If Err.Number <> 0 Then
  ' エラー処理
End If

UTF-8ファイルを保存しようとした場合にBOMが付加される

  • ADODB.StreamオブジェクトのsaveToFileメソッドでUTF-8のファイルを作成した場合、BOMが自動的に付加されるようです。BOMがついていると色々と面倒なことになりそうなので、できれば付加したくないところです。

このため、一度一時ファイルにBOMつきで出力し、その一時ファイルをBOMの部分を読み飛ばして読み込み、再度ファイルに出力するという手段を取ることで回避できるようです。

上記のように「UTF-8」を指定した場合、BOM付きのUTF-8で保存されてしまう。
BOMなしUTF-8は指定できないため、BOMなしにするにはBOMを除去する処理が必要になる。
具体的には以下のような処理を行う。

1. 一時ファイルに「UTF-8(BOM付き)」で出力する

2. 一時ファイルを4バイト目から読み込む(BOMが先頭3バイトのため)

3. 読み込んだ4バイト目以降を、出力ファイルに書き出す

4. 一時ファイルを削除する
忘れな〜い録 UTF-8(BOMなし)でファイルを保存する。(VBA) はてなブックマーク - 忘れな〜い録 UTF-8(BOMなし)でファイルを保存する。(VBA)

2009.11.17追記

対処方法が見つかりましたので、以下のエントリにまとめています。