简单的方法是在Python中读取文件的最后N行

时间:2014-11-02 05:34:45

标签: python file-io

我希望逐行读取文件,除了最后N行。我怎么知道在哪里停止,没有到达文件的末尾并回溯跟踪/丢弃最后的N行,在Python中?要求#lines = X,并且循环(X-N)是一个很好的方法来解决这个问题吗?

最简单/最恐怖的方式是什么?

4 个答案:

答案 0 :(得分:2)

除非您事先知道实际行数,否则您必须阅读整个文件。

但是我假设您希望处理除了N最后一行之外的行文件,您可以在不加载内存中的所有文件的情况下执行此操作,并且只保留N行的列表:

with open(file) as fd:
    lines = []
    try:
        for i in range(N):
            lines.append(next(fd))

        i = 0
        for line in fd:
            # process lines[i]
            print (lines[i].rstrip())
            lines[i] = line
            i = (i + 1) % N
    except StopIteration:
        print "less than %d lines" % (N,)

答案 1 :(得分:2)

三种不同的解决方案:

1)快速而肮脏,请参阅John的回答:

with open(file_name) as fid:
    lines = fid.readlines()
for line in lines[:-n_skip]:
    do_something_with(line)

这种方法的缺点是你必须首先读取内存中的所有行,这可能是大文件的问题。

2)两次通过

处理文件两次,一次计算行数n_lines,在第二次处理过程中只计算第一行n_lines - n_skip行:

# first pass to count
with open(file_name) as fid:
    n_lines = sum(1 for line in fid)

# second pass to actually do something
with open(file_name) as fid:
    for i_line in xrange(n_lines - n_skip):  # does nothing if n_lines <= n_skip
        line = fid.readline()
        do_something_with(line)

此方法的缺点是您必须迭代文件两次,在某些情况下可能会更慢。然而,好处是你的内存中永远不会有多行。

3)使用缓冲区,类似于Serge的解决方案

如果您只想对文件进行一次迭代,只有在知道行i存在时才能确定可以处理行i + n_skip。这意味着您必须先将n_skip行保留在临时缓冲区中。一种方法是实现某种FIFO缓冲区(例如,使用实现循环缓冲区的生成器函数):

def fifo(it, n):
    buffer = [None] * n  # preallocate buffer
    i = 0
    full = False
    for item in it:  # leaves last n items in buffer when iterator is exhausted
        if full:
            yield buffer[i]  # yield old item before storing new item
        buffer[i] = item
        i = (i + 1) % n
        if i == 0:  # wrapped around at least once
            full = True

使用一系列数字进行快速测试:

In [12]: for i in fifo(range(20), 5):
    ...:     print i,
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

您在文件中使用它的方式:

with open(file_name) as fid:
    for line in fifo(fid, n_skip):
        do_something_with(line)

请注意,这需要足够的内存来临时存储n_skip行,但这仍然比在第一个解决方案中读取内存中的所有行更好。

这三种方法中哪一种最好是在代码复杂性,内存和速度之间进行权衡,这取决于您的确切应用。

答案 2 :(得分:1)

要读取最后X行的所有行,您需要知道最后X行的开始位置。您将在某处获得此信息。 有几种方法可以获取此信息。

  1. 当你写文件时保存最后X行的位置。到达那个位置时停止阅读。
  2. 将行的位置存储在某处,这样可以追加到文件中。
  3. 你知道线条的大小。
    1. 每行可以具有相同的大小,您可以使用文件大小
    2. 计算它
    3. 每行至少有一个字符,因此您无需读取最后X个字符。

答案 3 :(得分:1)

鉴于我们知道文件必须被读到最后才能确定有多少行,这是我尝试阅读最后n行的“最简单/最恐怖的方式”:

with open(foo, 'r') as f:
    lines = f.readlines()[:-n]