見出し画像

【今さら極める VB6 -Part 1】文字列連結の100倍高速化(VB6 版 StringBuilder)

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ブロックで使用する場合

With New StringBuilder
   Call .Append("With ブロック")
   Call .AppendLine("を使います")
   Debug.Print .ToString()
End With

VB6 版 StringBuilder クラスのソースコード

StringBuilder.cls

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 に続きます。

この記事が気に入ったらサポートをしてみませんか?