簡體   English   中英

如何讀取具有特定字符串的文件的最后幾行?

[英]How to read n last lines of a file having a specific string?

我有一個日志文件,其中包含數據行和一些說明文本行。 我想從文件中讀取最后10個數據行。 我怎么能在Python中做到這一點? 我的意思是,是否有比使用更快的方式

for line in reversed(open("filename").readlines()):

然后解析文件。 我想它打開整個文件,如果日志文件很大,則速度很慢。 那么有一種方法可以打開文件的末尾並從中讀取數據嗎? 我需要的只是來自文件,Kes的文件的最后10行。 如果沒有10行具有,Kes ,它應該返回所有具有,Kes,Kes其順序與文件中出現的順序相同。

你必須越過第一(N - 10)行,但你可以聰明地做到這一點。 你消耗時間的事實並不意味着你也必須消耗內存。 在你的代碼中,你使用readlines()讀取所有行並返回它們的列表。 這是fileobject本身是一個類似迭代器的對象,你可以使用一個長度受限的容器,並將所有行插入其中,最后它只保留最后N行。 在python中,你可以使用一個deque ,其maxlen設置為10,為此:

from collections import deque

with open("filename") as f:
    last_ten_lines =  deque(f,maxlen=10)

關於你的最后一點,如果你想過濾具有單詞的行,Kes最好的方法是循環遍歷文件對象的反向。

from itertools import islice
def get_last_n(file_name, n=10):
""" Returns the last N filtered lines. """
    def loop_over():
        with open(file_name) as f:
            for line in reversed(f):
                if ",Kes" in line: 
                    yield line
    return islice(get_last_ten(), N)

您可以

  • 閱讀全部,將所有內容存儲在一個列表中,反轉所有內容,然后前10行包含,Kes
    • 你的方法 - 需要大量的存儲和時間
  • 使用Kasramvd的方法比法國更加優雅 - 利用可迭代和islice
  • 自己讀取每一行並檢查是否,Kes ,如果是這樣排隊:

from collections import deque

# create demodata
with open ("filename","w") as f:
    for n in range (20):
        for p in range(20):
            f.write("some line {}-{}\n".format(n,p))

        f.write("some line with {} ,Kes \n".format(n))

# read demodata
q = deque(maxlen=10)
with open("filename") as f:
    for line in f:           # read one line at time, not huge file at once
        if ',Kes' in line:   # only store line if Kes in it
            q.append(line)   # append line, size limit will make sure we store 10 at most

# print "remebered" data
print(list(q))

輸出:

['some line with 10 ,Kes \n', 'some line with 11 ,Kes \n', 'some line with 12 ,Kes \n', 
 'some line with 13 ,Kes \n', 'some line with 14 ,Kes \n', 'some line with 15 ,Kes \n', 
 'some line with 16 ,Kes \n', 'some line with 17 ,Kes \n', 'some line with 18 ,Kes \n', 
 'some line with 19 ,Kes \n']

你不會同時將整個文件放在RAM中,最多11行(curr line + deque持有10行,它只記住帶有,Kes行。)

您提出的代碼顯然效率不高:

  • 你把整個文件讀入內存
  • 你完全顛倒了行列表
  • 然后才搜索包含關鍵字的行。

我可以想象兩種可能的算法:

  1. 以正向順序掃描文件並存儲包含關鍵字的10行,每個新行替換舊版本。 代碼可能或多或少:

     to_keep = [None] * 10 index = 0 for line in file: if line.find(keyword) != -1: to_keep[index] = line index = (index + 1) % 10 

    如果文件中只有幾行包含關鍵字,並且從后面讀取也需要加載文件的很大一部分,那么應該可以接受

  2. 從末尾讀取塊中的文件,並在每個塊上應用上面的算法。 如果關鍵字足夠頻繁,只需要很少的塊就會更有效,但會稍微復雜一點:不可能尋找行但只能查找文件中的字節位置,所以你可以從中間開始一行或甚至在多字節字符的中間(考慮UTF-8),所以你應該保留第一個部分行並稍后將其添加到下一個塊。

import os os.popen('tail -n 10 filepath')。read()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM