如何从python文件的末尾开始读取行

如何从python文件的末尾开始读取行,python,file-io,Python,File Io,我需要知道如何在python中读取文件中的行,以便首先读取最后一行,并以这种方式继续,直到光标到达文件的开头。有什么想法吗 解决这个问题的一般方法是,按行反向读取文本文件,至少可以通过三种方法来解决 一般的问题是,由于每一行可以有不同的长度,您无法事先知道每一行在文件中的起始位置,也无法知道有多少行。这意味着您需要对问题应用一些逻辑 一般方法#1:将整个文件读入内存 使用这种方法,您只需将整个文件读入内存,在某种数据结构中,随后允许您反向处理行列表。堆栈、双链接列表甚至数组都可以做到这一点 优点

我需要知道如何在python中读取文件中的行,以便首先读取最后一行,并以这种方式继续,直到光标到达文件的开头。有什么想法吗

解决这个问题的一般方法是,按行反向读取文本文件,至少可以通过三种方法来解决

一般的问题是,由于每一行可以有不同的长度,您无法事先知道每一行在文件中的起始位置,也无法知道有多少行。这意味着您需要对问题应用一些逻辑

一般方法#1:将整个文件读入内存 使用这种方法,您只需将整个文件读入内存,在某种数据结构中,随后允许您反向处理行列表。堆栈、双链接列表甚至数组都可以做到这一点

优点:非常容易实现(据我所知,可能内置在Python中)
缺点:占用大量内存,读取大文件可能需要一段时间

一般方法#2:读取整个文件,存储行的位置 使用这种方法,您还可以读取整个文件一次,但不是将整个文件(所有文本)存储在内存中,而是将二进制位置存储在文件中每行的起始位置。您可以将这些位置存储在与第一种方法中存储行的数据结构类似的数据结构中

无论何时要读取X行,都必须从存储的该行起始位置重新读取文件中的该行

优点:几乎与第一种方法一样易于实施
缺点:读取大文件可能需要一些时间

一般方法#3:反向读取文件,然后“找出答案” 使用这种方法,您将从末尾按块或类似方式读取文件,并查看端点的位置。您基本上有一个缓冲区,比如4096字节,并处理该缓冲区的最后一行。当必须在该缓冲区中一次向后移动一行的处理到达缓冲区的开始时,需要从读取的第一个缓冲区之前的区域读取另一个缓冲区的数据,然后继续处理

这种方法通常更为复杂,因为您需要处理诸如在两个缓冲区上断开的行,而长的行甚至可以覆盖两个以上的缓冲区

然而,它需要的内存量最少,对于真正大的文件来说,这样做可能也值得,以避免先读取千兆字节的信息

优点:占用内存少,不需要先读取整个文件
缺点:实施起来非常困难,而且在所有的情况下都是正确的


网络上有许多链接显示了如何进行第三种方法:


一种简单的方法是首先创建一个临时反转文件,然后反转该文件中的每一行

import os, tempfile

def reverse_file(in_filename, fout, blocksize=1024):
    filesize = os.path.getsize(in_filename)
    fin = open(in_filename, 'rb')
    for i in range(filesize // blocksize, -1, -1):
        fin.seek(i * blocksize)
        data = fin.read(blocksize)
        fout.write(data[::-1])

def enumerate_reverse_lines(in_filename, blocksize=1024):
    fout = tempfile.TemporaryFile()
    reverse_file(in_filename, fout, blocksize=blocksize)
    fout.seek(0)
    for line in fout:
        yield line[::-1]

上面的代码将生成在开头而不是结尾带有换行符的行,并且没有尝试处理DOS/Windows样式的换行符(\r\n)。

此解决方案比我见过的任何其他解决方案都简单

def xreadlines_reverse(f, blksz=524288):
    "Act as a generator to return the lines in file f in reverse order."
    buf = ""
    f.seek(0, 2)
    pos = f.tell()
    lastn = 0
    if pos == 0:
        pos = -1
    while pos != -1:
        nlpos = buf.rfind("\n", 0, -1)
        if nlpos != -1:
            line = buf[nlpos + 1:]
            if line[-1] != "\n":
                line += "\n"
            buf = buf[:nlpos + 1]
            yield line
        elif pos == 0:
            pos = -1
            yield buf
        else:
            n = min(blksz, pos)
            f.seek(-(n + lastn), 1)
            rdbuf = f.read(n)
            lastn = len(rdbuf)
            buf = rdbuf + buf
            pos -= n
用法示例:

for line in xreadlines_reverse(open("whatever.txt")):
    do_stuff(line)

您还可以使用python模块文件向后读取。它将以节省内存的方式读取。它适用于Python 2.7和3

它支持“utf-8”、“拉丁语-1”和“ascii”编码。它将使用“\r”、“n”和“\r\n”作为新行

安装后,通过
pip install file\u read\u backwards
(v1.2.1),您可以通过以下方式向后(逐行)读取整个文件:


进一步的文档可以在

中找到,如果你查找“tail”,你会发现一些好的例子,例如:可能重复我曾经考虑过的方法1,因为readlines方法会使事情变得简单。。。但我会处理大文件。我将不得不考虑如何编写选项3……我添加了一些代码链接来实现这一点,但请注意,我不能推荐任何选项(也就是说,我没有尝试过它们,所以我不能推荐它们,并不是我不会,我只是不知道它们是否真的有效。)这不能正确处理无法查找的文件。在我的系统上,
sys.stdin.seek(x,y)
不会产生错误,
sys.stdin.tell()
返回一个整数,这使得很难辨别是否支持seek。最好的解决方案可能是尝试使用
os.lseek
#!/usr/bin/env python2.7

from file_read_backwards import FileReadBackwards

with FileReadBackwards("/path/to/file", encoding="utf-8") as frb:
    for l in frb:
         print l