String-Operationen sind wohl in den meisten Anwendungen zu finden. Sie gehören zu den absoluten Basics beim Codieren von Anwendungen in jeder Programmiersprache. In VB6 sind String-OP´s sehr sehr langsam und es wird vor Ihrer Verwendung immer gewarnt. Trotzdem wird man nie ohne Sie auskommen. Das einfache String-Building ist also langsam, und es wird Zeit, dass wir ihm ein Gaspedal verpassen. Thema heute ist das Generieren von Strings in Wiederholungen in VB6.
Nehmen wir dafür folgendes einfaches Beispiel vor:
For i = 0 to 5 b = b & "A" Next |
Wir bauen uns einen String das 6 "A" enthält. Wieviele Zeichen werden jetzt in b kopiert?
Beim 1. Durchgang ist es 1 Zeichen.
Beim 2. Durchgang werden 2 Zeichen (b="A" und "A") kopiert! Jetzt sind wir bei insgesamt 3 Zeichen!
Beim 3. Durchgang: b = b(="AA") & "A" ==> das sind ein plus von 3 Zeichen also haben wir bereits 6 Zeichen kopiert!! usw usw...
Also ergibt sich folgende Rechnung:
Anzahl von zu kopierenden Zeichen: 1+2+3+4+5+6 = 21 Zeichen!!!
Mehr dazu ist in 25 ASP TIPP´s zu finden.
http://dblabor.f4.fhtw-berlin.de/Lehre/asptips.htm
Wie kann man das Verbessern?
In dem wir Speicher reservieren und den String in den reservierten Speicher kopieren. Hier können wir als Ziel ein Byte-Array verwenden, da ASCII-Zeichen zum Byte-Format voll kompatibel sind. Das kopieren erledigen wir mit der API "CopyMemory".
Wie schnell kann es dadurch werden?
Sehr schnell! Folgendes Beispiel zeigt 10000 Wiederholungen, wobei der Wert "ppedv AG" immer und immer wieder angefügt wird. Hier ist der Vergleich zwischen Normal (b = b & "wert") und der "CStringBuilder"-Klasse.
2,8 Sekunden mit Normal und 0,06 Sekunden mit der CStringBuilder-Klasse! Getestet mit einem P3, 500MH und Win2000.
Das Sample mit allen Sources gibt es unten zum Download.
Das Verwenden der Klasse ist sehr einfach.
statt (Normal)...
For i = 0 To 10000 sVal = sVal & "ppedv AG" Next txtErg.Text = sVal |
folgendes (CStringBuilder)...
Dim oStrBuilder As New CStringBuilder For i = 0 To 10000 oStrBuilder.Add "ppedv AG" Next txtErg.Text = oStrBuilder.Value |
Werfen wir einen Blick auf die Klasse "CStringBuilder"!
Option Explicit Private m_abyteString() As Byte ' beinhaltet (B)Strings als Byte-Array Private m_lSize As Long ' beinhaltet die tatsächliche Grösse des gesamten Strings in Byte (Anzahl der Zeichen * 2) ' Kopiert Speicher-Bereiche. Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) ' Die Add Funktion ist der Kern der Klasse und erledigt das Anfügen von Strings ' wie b = b & "wert" Public Sub Add(ByVal Value As String) Dim lSize As Long ' Länge in Byte = Zeichen * 2 lSize = LenB(Value) On Error GoTo Fehler ' vor Array-Buffer-Überlauf die Grösse des Arrays verdoppeln. If (m_lSize + lSize) > (UBound(m_abyteString) + 1) Then ReDim Preserve m_abyteString((UBound(m_abyteString) * 2) + 1) End If ' String-Wert zu Byte-Array hinzufügen. CopyMemory ByVal VarPtr(m_abyteString(m_lSize)), ByVal StrPtr(Value), lSize m_lSize = m_lSize + lSize ' reale String-Grösse in Byte speichern Exit Sub Fehler: If Err.Number = 9 Then '..... Else Err.Raise Err.Number, Err.Source, Err.Description End If End Sub ' Diese Funktion stellt den erstellten String-Wert bereit. ' Byte-Array und String sind als kompatible Datentypen. Public Property Get Value() As String Value = CStr(LeftB(m_abyteString, m_lSize)) End Property ' Buffer-Grösse festlegen(Let) und veräussern(Get) Public Property Let BufferSize(ByVal par As Long) ReDim m_abyteString((par * 2) - 1) '--> in Byte-Länge konvertieren End Property Public Property Get BufferSize() As Long On Error GoTo Fehler BufferSize = (UBound(m_abyteString) + 1) / 2 '--> in Zeichen-Länge konvertieren Exit Property Fehler: Err.Clear BufferSize = 0 End Property Private Sub Class_Initialize() ReDim m_abyteString(511) ' Default String-Buffer festsetzen End Sub |
BufferSize
Mit Hilfe der "BufferSize"-Eigenschaft kann die Grösse des String-Buffers optimiert werden. Natürlich nur, wenn man weiss wie Gross die Zeichenkette werden wird. Dann muss das Byte-Array nicht mehr resized werden und das spart zusätzlich etwas Zeit.
Alle Sources gibt´s unten zum Download.