おそらく、パターン スキャンが非効率的です。このようなコードを使用すると、約 1/20 秒で 7 MB のファイルのパターンをスキャンできます。このようなコードを本当に使用したい場合は、修正する必要があることに注意してください。一致を見ていないことに気付いたときに、MatchedLength を常に 0 に戻すことはできませんが、この特定のパターンでは機能します。パターンを前処理して、一致が見つからない場合に何をリセットするかを知る必要がありますが、それによってアルゴリズムに大幅な時間が追加されることはありません。アルゴリズムを正しく完成させる努力をすることはできますが、あなたの質問が単にパフォーマンスに関するものであれば、今はそうしません。正しく実行すれば、大きなファイルをすばやくスキャンできることを示しているだけです。
Sub Main(ByVal args As String())
If args.Length < 1 Then Return
Dim startTime As Long = Stopwatch.GetTimestamp()
Dim pattern As Byte()
pattern = System.Text.Encoding.UTF8.GetBytes("SFMB")
Dim bufferSize As Integer = 4096
Using reader As New System.IO.FileStream(args(0), IO.FileMode.Open, _
Security.AccessControl.FileSystemRights.Read, IO.FileShare.Read, bufferSize, IO.FileOptions.SequentialScan)
Dim buffer(bufferSize - 1) As Byte
Dim readLength = reader.Read(buffer, 0, bufferSize)
Dim matchedLength As Integer = 0
Dim searchPos As Integer = 0
Dim fileOffset As Integer = 0
Do While readLength > 0
For searchPos = 0 To readLength - 1
If pattern(matchedLength) = buffer(searchPos) Then
matchedLength += 1
Else
matchedLength = 0
End If
If matchedLength = pattern.Length Then
Console.WriteLine("Found pattern at position {0}", fileOffset + searchPos - matchedLength + 1)
matchedLength = 0
End If
Next
fileOffset += readLength
readLength = reader.Read(buffer, 0, bufferSize)
Loop
End Using
Dim endTime As Long = Stopwatch.GetTimestamp()
Console.WriteLine("Search took {0} seconds", (endTime - startTime) / Stopwatch.Frequency)
End Sub
編集
複数のパターンを一度に一致させる方法について、いくつかの考えを次に示します。これは私の頭のてっぺんから外れており、コードをコンパイルしようとはしていません。
パターンのステータスに関する情報を含むクラスを作成します。
Class PatternInfo
Public pattern As Byte()
Public matchedBytes As integer
End Class
チェックする必要があるすべてのパターンを追跡する変数を宣言し、パターンの最初のバイトでインデックスを付けてすばやく検索できるようにします。
Dim patternIndex As Dictionary(Of Byte, IEnumerable(Of PatternInfo))
現在一致する可能性のあるすべてのパターンをチェックして、次のバイトもこれらのパターンに一致するかどうかを確認します。そうでない場合は、その位置でそのパターンを見るのをやめます。
Dim activePatterns As New LinkedList(Of PatternInfo)
Dim newPatterns As IEnumerable(Of PatternInfo)
For Each activePattern in activePatterns.ToArray
If activePattern.pattern(matchedBytes) = buffer(searchPos) Then
activePattern.matchedBytes += 1
If activePattern.matchedBytes >= activePattern.pattern.Length Then
Console.WriteLine("Found pattern at position {0}", searchPos - matchedBytes + 1)
End If
Else
activePatterns.Remove(activePattern)
End If
Next
現在のバイトが、探している新しいパターンの始まりのように見えるかどうかを確認してください。その場合は、アクティブなパターンのリストに追加します。
If patternIndex.TryGetValue(buffer(searchPos), newPatterns) Then
For Each newPattern in newPatterns
activePatterns.Add(New PatternInfo() With { _
.pattern = newPattern.pattern, .matchedBytes = 1 }
Next
End If