如何在Python中实现`tail -1`

问题描述 投票:0回答:2

我有一些非常大的文件(超过 1 亿行)。
我需要读他们的最后一行。
由于我是 Linux 用户,因此在 shell/脚本中我使用“tail”。

有没有办法在Python中快速读取文件的最后一行?
也许,使用“seek”,但我不知道这一点。

我得到的最好的就是这个:

from subprocess import run as srun

file = "/my_file"
proc = srun(['/usr/bin/tail', '-1', file], capture_output=True)
last_line = proc.stdout

我尝试的所有其他 pythonic 代码都比调用外部 /usr/bin/tail

我还阅读了这些不能满足我需求的帖子:
如何实现 tail -F 的 Python 等价物?
头尾在一条线上
因为我想要一定的执行速度并避免内存过载。

编辑: 我尝试根据评论了解我的理解,然后……

我的行为很奇怪:

>>> with open("./Python/nombres_premiers", "r") as f:
...     a = f.seek(0,2)
...     l = ""
...     for i in range(a-2,0,-1):
...        f.seek(i)
...        l = f.readline() + l
...        if l[0]=="\n":
...           break
... 
1023648626
1023648625
1023648624
1023648623
1023648622
1023648621
1023648620
1023648619
1023648618
1023648617
1023648616
>>> l
'\n2001098251\n001098251\n01098251\n1098251\n098251\n98251\n8251\n251\n51\n1\n'
>>> with open("./Python/nombres_premiers", "r") as f:
...     a = f.seek(0,2)
...     l = ""
...     for i in range(a-2,0,-1):
...        f.seek(i)
...        l = f.readline()
...        if l[0]=="\n":
...           break
... 
1023648626
1023648625
1023648624
1023648623
1023648622
1023648621
1023648620
1023648619
1023648618
1023648617
1023648616
>>> l
'\n'

如何获得

l = 2001098251

python-3.x implementation tail
2个回答
2
投票

tail 不支持任意长的行——它获取文件的最后一个块并从那里迭代。自己做同样的事情可能看起来像:

def last_line(f, bufsize=4096):
    end_off = f.seek(0, 2)
    f.seek(max(end_off - bufsize, 0), 0)
    lastline = None
    while (line := f.readline()):
        if line[-1] == '\n':
            lastline = line
        else:
            break # last line is not yet completely written; ignore it
    return lastline[:-1] if lastline is not None else None

import sys
print(last_line(open(sys.argv[1], 'r')))

请注意,如果您想在文件随着时间的推移而编辑时继续阅读新内容,则应该使用 inotify 来监视更改。 https://stackoverflow.com/a/78969468/14122演示了这一点。


0
投票

使用 seek()read()readline(),
我可以快速检索文本文件的最后一行:

with open("My_File", "r") as f:
     n = f.seek(0,2)
     for i in range(n-2, 0, -1):
             f.seek(i)
             if f.read(1)=="\n":
                     s = f.readline().replace("\n", "")
                     break

编辑:如果文件只有 1 行,则将

range(n-2, 1, -1)
更改为
range(n-2, 0, -1)

Edit2:如果没有换行符,则将
s = f.readline()[:-1]
替换为
s = f.readline().replace("\n", "")

© www.soinside.com 2019 - 2024. All rights reserved.