ADODB.Stream
クラスの WriteText
メソッドを使用することにより、文字列の連結を高速に行うことができます。
手法と技術的背景
文字列連携のパフォーマンス
String
はイミュータブル(不変)であり、生成後に値を変更できないため、文字列を連結する際は新たにインスタンスを生成することになります。
String
の連結を繰り返すとメモリを消費し、処理速度が大きく低下するため、.NET では変更可能な文字列クラス StringBuilder
の使用が推奨されています。
VB6 にはこれに相当するクラスが用意されていませんので、自前で作りました。
ADO によるストリームアクセス
ADO(Microsoft ActiveX Data Objects)は、古くは MDAC(Microsoft Data Access Components)、Vista 以降は Windows DAC(Windows Data Access Components)の一部として、Windows OS に含まれています。
VB6 でデータベースにアクセスする際の標準的なライブラリとして広く使用されていますが、「ADO の基礎」に列挙されているように、データベース以外の「データソース」も扱うことができるように設計、実装されています。
ADODB.Stream
クラスは、一般的にはファイルアクセスに使用することが多いと思いますが、メモリ内で使用することもできます。
改善例
ケース
20文字 × 10,000行 を行ごとに連結
処理時間
40秒 → 0.4秒(100倍高速化)
使用イメージ
下記 StringBuilder
クラスを使って、
sLines = sLines & "Line" & vbCrLf
に相当する処理を
sb.AppendLine("Line")
のように記述し、ToString()
で連結後の文字列を取得することができます。
Dim sb As StringBuilder
Set sb = New StringBuilder
Call sb.Append("変数")
Call sb.AppendLine("を使います")
Debug.Print sb.ToString()
With New StringBuilder
Call .Append("With ブロック")
Call .AppendLine("を使います")
Debug.Print .ToString()
End With
VB6 版 StringBuilder クラスのソースコード
Option Explicit
'改行文字
Public Enum LineSeparatorsEnum
adCR = 13
adCRLF = -1
adLF = 10
End Enum
'ストリームオブジェクト
Private mStream As Object 'ADODB.Stream
'改行文字 ※既定は CR+LF
Public Property Get LineSeparator() As LineSeparatorsEnum
LineSeparator = mStream.LineSeparator
End Property
Public Property Let LineSeparator(ByVal e As LineSeparatorsEnum)
mStream.LineSeparator = e
End Property
'文字列の長さ
Public Property Get Length() As Long
If mStream.Size <= 0 Then
Length = mStream.Size
Else
'Len(ToString()) だと遅い。
'UTF-16 なので1文字2バイトと換算。Len 関数同様、サロゲートペアには対応していない。
Length = (mStream.Size / 2) - Len(vbNullChar)
End If
End Property
'コンストラクタ
Private Sub Class_Initialize()
Set mStream = CreateObject("ADODB.Stream")
mStream.Type = 2 'adTypeText
LineSeparator = adCRLF
'Charset は既定の "Unicode"(UTF-16)
Call mStream.Open
End Sub
'文字列を追加する。
Public Function Append(ByVal s As String) As StringBuilder
Call mStream.WriteText(s, 0) 'adWriteChar
Set Append = Me
End Function
'改行付で文字列を追加する。
Public Function AppendLine(Optional ByVal s As String = "") As StringBuilder
Call mStream.WriteText(s, 1) 'adWriteLine
Set AppendLine = Me
End Function
'文字列化する。
Public Function ToString() As String
mStream.Position = 0
ToString = mStream.ReadText()
mStream.Position = mStream.Size
End Function
'デストラクタ
Private Sub Class_Terminate()
Call mStream.Close
End Sub
これで終わりません。
翌日公開の Part 2 に続きます。