Возможно, ваше сканирование шаблона неэффективно. Я могу сканировать шаблон в файле размером 7 МБ примерно за 1/20 секунды, используя такой код. Обратите внимание: если вы действительно хотите использовать подобный код, вы должны внести исправление. Вы не всегда можете установить 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
EDIT
Вот некоторые мысли о том, как вы можете сопоставить несколько шаблонов одновременно. Это не в моей голове, и я не пытался скомпилировать код:
Создайте класс, который будет содержать информацию о состоянии шаблона:
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