【问题标题】:How would I go about printing the last line in a large text file?我将如何在大文本文件中打印最后一行?
【发布时间】:2016-08-13 20:27:03
【问题描述】:

我将如何打印文本文件中的最后一行,该文本文件大约是 612 MB,并且有大约 400 万行由 This is a line 组成的文本。到目前为止,我有:

文件.py

f = open("foo.txt","r+")
datalist = []
for line in f:
    datalist.append(line)
print(datalist[-1])

我在代码中看到的唯一问题是它使用了大量内存。我听说有人改用os.lseek,但我不知道如何实现它。

【问题讨论】:

  • 通过subprocess 致电tail?它向后读取文件。无法击败它(除非在 python 中重新实现它)。你在 Linux 上吗?
  • @jDo 遗憾的是,我在 Windows 10 上
  • print("This is a line")?我不确定如何理解您对输入格式的描述。
  • @Alex 好的...我认为this class 做得很好。它基本上是 Linux 的headtail 的python 重新实现。如果您在此处或在 google 上搜索“read file backwards tail python”,还有很多其他示例。

标签: python python-3.x


【解决方案1】:

这是一个非常简单的改进,一次只存储一行:

f = open("foo.txt","r")
data = None
for line in f:
    data = line
print(data)

或者你可以在循环之后获取最终的循环值:

f = open("foo.txt","r")
line = None
for line in f:
    pass
print(line)

请注意,在此示例中,如果文件为空,line 将为 None(这是初始分配给 line 的原因)。

【讨论】:

    【解决方案2】:

    如果你只需要最后一行,就把其他的都扔掉。

    with open('foo.txt') as f:
        for line in f:
            pass
    
    # `line` is the last line of the file.
    

    从文件末尾开始并按字节向后移动,直到找到\n,然后读取,会更快(但可读性要差得多)。

    with open('foo.txt') as f:
        fd = f.fileno()
        os.lseek(fd, 0, os.SEEK_END)
        while True:
            ch = os.read(fd, 1)
            if ch == b'\n':
                line = f.read()
                break
            else:
                os.lseek(fd, -2, os.SEEK_CUR)
    
    # `line` is the last line of the file
    

    这是通过从末尾读取文件,查找第一个换行符,然后从那里向前读取来实现的。

    【讨论】:

    • 当我运行你的代码时,我得到了TypeError: an integer is required (got type _io.TextIOWrapper)
    • @Alex 哎呀,已修复。
    • 可以通过分块查找和读取以及使用rfind查找最后一个'\n'来提高向后读取解决方案的效率。此外,将换行符作为文件的最后一个字符的处理相当微妙(代码寻找到最后,什么也不读,然后返回两个字符,跳过文件的最后一个字符!我认为这实际上产生了正确的结果,但乍一看并不明显。)理想情况下,如果只有一行并且您最终尝试从文件的左侧寻找,或者文件为空,则还应该进行一些处理。
    • @user2357112 同意这是一个时髦的解决方案,不能解决所有极端情况。这不是生产代码,而是 Stack Overflow 示例 :)。我实际上没有想过如何处理以换行符结尾的文件,而这只是偶然成功。
    • @user2357112 jDo 在问题的 cmets 中链接了一个漂亮的助手类,它可以更优雅地完成这一切。
    【解决方案3】:

    一个快速的改进方法是丢弃datalist,只保存最近的一行,因为这就是你关心的全部。

    f = open("foo.txt","r+")
    for line in f:
        pass
    print(line)
    

    我想还有其他更有效的方法;我只想提供一个直接派生于您的代码的代码。

    【讨论】:

      【解决方案4】:

      您不需要将每一行附加到列表中。只需使用循环变量:

      line = None  # prevents a NameError if the file is empty
      
      with open("foo.txt", "r+") as f: 
          for line in f:
              pass
      print(line)
      

      【讨论】:

        【解决方案5】:

        查看 collections 模块中的 deque。有一个方法可以查看文件中的最后 'n' 行;即尾巴。

        https://docs.python.org/2/library/collections.html#deque-recipes

        def tail(filename, n=10):
            'Return the last n lines of a file'
            return deque(open(filename), n)
        

        【讨论】:

        • 这似乎比 OP 当前方法的性能要低得多。
        猜你喜欢
        • 2022-06-15
        • 1970-01-01
        • 2012-10-14
        • 1970-01-01
        • 2015-03-05
        • 2016-05-21
        • 2016-09-28
        • 2020-08-08
        相关资源
        最近更新 更多