Поскольку данные являются последовательными, если начало и конец интересующей области находятся рядом с началом файла, то чтение с конца файла (чтобы найти подходящую конечную точку) все еще является плохим решением!
Я написал некоторый код, который будет быстро находить начальную и конечную точки, как вам требуется, этот подход называется бинарный поиск и похож на классическую детскую игру в догадки "выше или ниже"!
Скрипт читает пробную строку посередине между lower_bounds
и upper_bounds
(первоначально SOF и EOF) и проверяет критерии соответствия.Если искомая строка более ранняя, то она снова угадывает, читая строку на полпути между lower_bound
и предыдущим испытанием чтения (если оно выше, то оно разделяется между его предположением и верхней границей).Таким образом, вы продолжаете перебирать верхнюю и нижнюю границы - это дает самое быстрое из возможных решений «в среднем».
Это должно быть очень быстрое решение (войдите в основание 2 числа строк !!).Например, в наихудшем из возможных случаев (поиск строки 999 из 1000 строк), использование бинарного поиска займет всего 9 строк!(из миллиарда строк потребуется всего 30 ...)
Допущения для приведенного ниже кода:
- Каждая строка начинается с информации о времени.
- Времена уникальны - если нет, то при обнаружении совпадения вам придется проверять вперед или назад, чтобы включить или исключить все записи с совпадающим временем, в зависимости от ситуации (если требуется).
- Забавно, но это рекурсивная функция, поэтому количество строк в вашем файле ограничено 2 ** 1000 (к счастью, это позволяет довольно большой файл ...)
Далее:
- Это может быть адаптировано для чтения в произвольных блоках, а не в виде строки, если это предпочтительно.Как предложил Дж. Ф. Себастьян.
- В своем первоначальном ответе я предложил этот подход, но с использованием linecache.getline , хотя это возможно, его неуместно для больших файлов, так как он читает весь файл в память (таким образом,
file.seek()
лучше), спасибо TerryE и JF Sebastian за указание на это.
import datetime
def match(line):
lfmt = '%Y-%m-%d %H:%M:%S'
if line[0] == '[':
return datetime.datetime.strptime(line[1:20], lfmt)
def retrieve_test_line(position):
file.seek(position,0)
file.readline() # avoids reading partial line, which will mess up match attempt
new_position = file.tell() # gets start of line position
return file.readline(), new_position
def check_lower_bound(position):
file.seek(position,0)
new_position = file.tell() # gets start of line position
return file.readline(), new_position
def find_line(target, lower_bound, upper_bound):
trial = int((lower_bound + upper_bound) /2)
inspection_text, position = retrieve_test_line(trial)
if position == upper_bound:
text, position = check_lower_bound(lower_bound)
if match(text) == target:
return position
return # no match for target within range
matched_position = match(inspection_text)
if matched_position == target:
return position
elif matched_position < target:
return find_line(target, position, upper_bound)
elif matched_position > target:
return find_line(target, lower_bound, position)
else:
return # no match for target within range
lfmt = '%Y-%m-%d %H:%M:%S'
# start_target = # first line you are trying to find:
start_target = datetime.datetime.strptime("2012-02-01 13:10:00", lfmt)
# end_target = # last line you are trying to find:
end_target = datetime.datetime.strptime("2012-02-01 13:39:00", lfmt)
file = open("log_file.txt","r")
lower_bound = 0
file.seek(0,2) # find upper bound
upper_bound = file.tell()
sequence_start = find_line(start_target, lower_bound, upper_bound)
if sequence_start or sequence_start == 0: #allow for starting at zero - corner case
sequence_end = find_line(end_target, sequence_start, upper_bound)
if not sequence_end:
print "start_target match: ", sequence_start
print "end match is not present in the current file"
else:
print "start match is not present in the current file"
if (sequence_start or sequence_start == 0) and sequence_end:
print "start_target match: ", sequence_start
print "end_target match: ", sequence_end
print
print start_target, 'target'
file.seek(sequence_start,0)
print file.readline()
print end_target, 'target'
file.seek(sequence_end,0)
print file.readline()