由於數據是連續的,如果開始和感興趣的區域的結束是接近文件的開頭,然後閱讀從文件的末尾(找到匹配的終點)仍然是一個不好的解決方案!
我寫了一些代碼,可以根據需要快速找到開始點和結束點,這種方法被稱爲binary search,類似於經典兒童「更高或更低」的猜謎遊戲!
該腳本讀取lower_bounds
和upper_bounds
(最初是SOF和EOF)之間的試行線,並檢查匹配標準。如果所尋找的線路較早,則通過讀取lower_bound
與之前的讀取試驗之間的中間線(如果其更高,則其在猜測和上限之間分開),再次猜測。因此,您不斷在上下限之間進行迭代 - 這會產生最快的「平均」解決方案。
這應該是一個真正的快速解決方案(登錄到第2行的基數!!)。例如,在最壞的情況下(查找1000行中的999行),使用二分查找只需要9行讀取! (從十億線將只需30 ...)
爲下面的代碼
假設:
- 每一行與時間信息開始。
- 時間是唯一的 - 如果沒有,當發現匹配時,您必須檢查向後或向前以適當(如果需要)包含或排除具有匹配時間的所有條目。
- 有趣的是,這是一個遞歸函數,因此文件的行數限制爲2 ** 1000(幸運的是,這允許相當大的文件...)
此外:
- 這可適於在任意塊來讀取,而不是通過線,如果優選的。正如J.F.塞巴斯蒂安所建議的那樣。
- 在我原來的答案中,我建議這種方法,但使用linecache.getline,雖然這可能是不適合大文件,因爲它將整個文件讀入內存(因此
file.seek()
是優越的),這要感謝TerryE和J.F. Sebastian指出的。
進口日期時間
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()
你可以發佈你的日誌文件? – kev 2012-03-11 08:27:50
忽略kev的笑話,你應該看看你的日誌文件旋轉策略。讓任何日誌文件變得這麼大是不好的做法。 – TerryE 2012-03-11 11:00:16
'logrotate'工具是去這裏的方式 - 它存在以防止發生這種事情。 – Daenyth 2012-03-11 17:16:38