Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何读取具有特定字符串的文件的最后n行?_Python_Python 3.x_File_Iterator - Fatal编程技术网

Python 如何读取具有特定字符串的文件的最后n行?

Python 如何读取具有特定字符串的文件的最后n行?,python,python-3.x,file,iterator,Python,Python 3.x,File,Iterator,我有一个日志文件,其中有数据行和一些解释文本行。我想从文件中读取最后10行数据。我如何用Python实现它?我是说,有没有比使用更快的方法 for line in reversed(open("filename").readlines()): 然后解析文件。我猜它会打开整个文件,如果日志文件很大,则速度会很慢。那么,有没有一种方法可以只打开文件的末尾并从中读取数据呢?我只需要一个文件的最后10行,其中包含文本,Kes。如果没有10行包含,Kes,则它应该按照文件中显示的顺序返回所有包含,Kes

我有一个日志文件,其中有数据行和一些解释文本行。我想从文件中读取最后10行数据。我如何用Python实现它?我是说,有没有比使用更快的方法

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

然后解析文件。我猜它会打开整个文件,如果日志文件很大,则速度会很慢。那么,有没有一种方法可以只打开文件的末尾并从中读取数据呢?我只需要一个文件的最后10行,其中包含文本
,Kes
。如果没有10行包含
,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
的行,最好的方法是在file对象的反面循环

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)
导入操作系统 os.popen('tail-n10 filepath').read()

您可以

  • 全部读取、全部存储在列表中、全部反转并获取包含Kes的前10行
    • 您的方法-占用大量的存储空间和时间
  • 使用Kasramvd的方法,francly比这一个优雅得多-利用iterable和islice
  • 自己阅读每一行,检查其中是否有Kes,如果有,请排队:

输出:

['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
的行。

您建议的代码显然没有效率:

  • 您将整个文件读入内存
  • 您可以完全反转行列表
  • 然后才搜索包含关键字的行
我可以想象两种可能的算法:

  • 按向前顺序扫描文件,并存储10行包含关键字的内容,每行新内容替换旧内容。代码可能或多或少为:

    to_keep = [None] * 10
    index = 0
    for line in file:
        if line.find(keyword) != -1:
            to_keep[index] = line
            index = (index + 1) % 10
    
    如果文件中只有几行包含关键字,并且从后面读取也需要加载文件的大部分内容,那么这应该是可以接受的

  • >p>从结尾读取块,并在每个块上应用上面的算法。如果关键字足够频繁,只需要很少的块,这将是更有效的,但会稍微复杂一些:不可能在文件中查找行,而不可能搜索到字节位置,因此可以在中间行,甚至可以在中间开始。e是一个多字节字符(考虑UTF-8),所以您应该保留第一个部分行,然后将其添加到下一个块中


    您可以搜索到文件的结尾,但这意味着您需要自己执行反向行解析…可能是重复的,具体来说,您不希望@ThomWiggers立即出现。我刚刚检查了源代码:它会的。在中相同。@OP:这个答案与您正在编写的代码相同:它将读取文件的所有行。@ThomWiggers它不是等价的。OPs解决方案将所有行读取到一个列表中,反转整个列表,然后开始解析它。iterable只会触及下一行-因此它所需的内存远远少于OPs。这比我的要好:)可惜我只能+1-1。我现在没有时间为此编写代码,但是如果你在评论中问我,我可以。谢谢,但是我可以根据我的需要修改Patrick Artner的代码。@Patrick Artner:看起来我应该测试我的代码。。。固定的。非常感谢您的关注。
    to_keep = [None] * 10
    index = 0
    for line in file:
        if line.find(keyword) != -1:
            to_keep[index] = line
            index = (index + 1) % 10