Я работаю над проектом, в котором я ищу фрагмент данных в большом текстовом файле (большой - относительный, размер файла составляет около 1 гигабайта). Я ищу токен, и мне нужна долларовая стоимость сразу после этого токена. Например,
это токен 9 999 999,99
Итак, вот как я подхожу к этой проблеме. После небольшого анализа выяснилось, что токен обычно находится ближе к концу файла, поэтому я подумал, что начну поиск с конца файла. Вот код, который у меня есть (vb.net):
Dim sToken As String = "This is a token"
Dim sr As New StreamReader(sFileName_IN)
Dim FileSize As Long = GetFileSize(sFileName_IN)
Dim BlockSize As Integer = CInt(FileSize / 1000)
Dim buffer(BlockSize) As Char
Dim Position As Long = -BlockSize
Dim sBuffer As String
Dim CurrentBlock As Integer = 0
Dim Value As Double
Dim i As Integer
Dim found As Boolean = False
While Not found And CurrentBlock < 1000
CurrentBlock += 1
Position = -CurrentBlock * BlockSize
sr.BaseStream.Seek(Position, SeekOrigin.End)
i = sr.ReadBlock(buffer, 0, BlockSize)
sBuffer = New String(buffer)
found = SearchBuffer(sBuffer, sToken, Value)
End While
GetFileSize - это функция, которая возвращает размер файла. SearchBuffer - это функция, которая будет искать токен в строке. Я не знаком с регулярными выражениями, но изучу их для этой функции.
В основном я читаю небольшой фрагмент файла, ищу его, и если я не нахожу его, загружаю другой фрагмент и так далее ...
Я на правильном пути или есть лучший способ?





Я думаю, вы правильно поняли, что разбили файл на части. Однако вы можете захотеть читать фрагменты в разрывах строк, а не в установленном количестве байтов. В вашей текущей реализации, если токен находится на границе в 1000 байт, он может быть разрезан пополам, что помешает вам найти его. То же самое может привести к отключению данных.
Если вы собираетесь использовать куски, было бы разумно использовать блоки, кратные 512 байтам, и искать по 512-байтовому выравниванию, потому что это будет более эффективно при доступе к диску (который в конечном итоге будет в Блоки по 512 байт).
Могут быть и другие уровни детализации, даже лучше, но 512 было бы хорошим началом.
Если вы хотите сделать что-то более сложное, но, возможно, быстрее, вы можете посмотреть на асинхронное чтение блоков, чтобы искать один, пока загружается следующий.
Таким образом, вы можете выполнять поиск одновременно с загрузкой данных в память.
Я должен сказать, что, если ваш поиск не очень дорог, время чтения с диска, вероятно, будет полностью доминировать над этим, и такое сложное перекрытие не будет стоить дополнительных сложностей.
Подождите, народ ...
Что делать, если токен разбит между двумя кусками? Вы об этом думали?
Вы всегда можете выполнить поиск в файле с помощью FileStream (или продолжить поиск по своему усмотрению). Если вы решите использовать подход FileStream, то вам нужно будет сделать что-то вроде этого:
Dim stream As New FileStream("something.txt")
Dim findBytes As [Byte]() = BitConverter.GetBytes("whatever")
Dim f As Integer = 0
' remaining = Length - Position
While stream.Length - stream.Position > 0
If stream.ReadByte() = findBytes(f) Then
If ++f >= findBytes.Length Then
Console.WriteLine(stream.Position)
Exit While
End If
Else
f = 0
End If
End While
Замечу, что я использовал конвертер C# в vb, потому что мне не нравится vb.
Основная идея касается простого поиска в блоке строки. Это довольно просто, если вы хотите добавить чтение блоками.
«Что делать, если жетон разбивается между двумя кусками? Вы об этом думали?»
Сделали это совсем недавно. Я сохранил CurrentBlock в PreviousBlock, прежде чем перезаписать CurrentBlock, затем соединю два блока и проверьте, нет ли радости в поиске искомого слова! Работает хорошо. Поисковый запрос не может уйти, если поисковый запрос не превышает длину блока.