读取经常更新的文件

2025-02-11 09:50:00
admin
原创
38
摘要:问题描述:我目前正在 Linux 系统上用 Python 编写一个程序。目标是读取日志文件并在找到特定字符串时执行 bash 命令。另一个程序不断写入日志文件。我的问题是:如果我使用该方法打开文件,open()我的 Python 文件对象是否会随着实际文件被其他程序写入而更新,还是我必须在一定时间间隔内重新打...

问题描述:

我目前正在 Linux 系统上用 Python 编写一个程序。目标是读取日志文件并在找到特定字符串时执行 bash 命令。另一个程序不断写入日志文件。

我的问题是:如果我使用该方法打开文件,open()我的 Python 文件对象是否会随着实际文件被其他程序写入而更新,还是我必须在一定时间间隔内重新打开该文件?

更新:感谢到目前为止的回答。我可能应该提到该文件是由 Java EE 应用程序写入的,因此我无法控制何时将数据写入其中。我目前有一个程序,它每 10 秒重新打开文件一次,并尝试从文件中上次读取的字节位置读取。目前它只是打印出返回的字符串。我希望该文件不需要重新打开,但读取命令会以某种方式访问​​ Java 应用程序写入文件的数据。

#!/usr/bin/python
import time

fileBytePos = 0
while True:
    inFile = open('./server.log','r')
    inFile.seek(fileBytePos)
    data = inFile.read()
    print data
    fileBytePos = inFile.tell()
    print fileBytePos
    inFile.close()
    time.sleep(10)

感谢您对 pyinotify 和生成器的提示。我将研究这些内容以找到更好的解决方案。


解决方案 1:

我建议你看一下 David Beazley 的Python 生成器技巧,尤其是第 5 部分:处理无限数据。它将tail -f logfile实时处理相当于 Python 的命令。

# follow.py
#
# Follow a file like tail -f.

import time
def follow(thefile):
    thefile.seek(0,2)
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.1)
            continue
        yield line

if __name__ == '__main__':
    logfile = open("run/foo/access-log","r")
    loglines = follow(logfile)
    for line in loglines:
        print line,

解决方案 2:

“一次互动胜过千言万语”

>>> f1 = open("bla.txt", "wt")
>>> f2 = open("bla.txt", "rt")
>>> f1.write("bleh")
>>> f2.read()
''
>>> f1.flush()
>>> f2.read()
'bleh'
>>> f1.write("blargh")
>>> f1.flush()
>>> f2.read()
'blargh'

换句话说 - 是的,一个“打开”就可以了。

解决方案 3:

这是Jeff Bauer答案的稍作修改的版本,它可以防止文件截断。如果您的文件正在被处理,则非常有用logrotate

import os
import time

def follow(name):
    current = open(name, "r")
    curino = os.fstat(current.fileno()).st_ino
    while True:
        while True:
            line = current.readline()
            if not line:
                break
            yield line

        try:
            if os.stat(name).st_ino != curino:
                new = open(name, "r")
                current.close()
                current = new
                curino = os.fstat(current.fileno()).st_ino
                continue
        except IOError:
            pass
        time.sleep(1)


if __name__ == '__main__':
    fname = "test.log"
    for l in follow(fname):
        print "LINE: {}".format(l)

解决方案 4:

由于您针对的是 Linux 系统,因此可以使用pyinotify在文件发生更改时通知您。

还有这个技巧,可能对你有用。它用来file.seek做什么tail -f

解决方案 5:

我不是这方面的专家,但我认为您必须使用某种观察者模式来被动地观察文件,然后在发生变化时触发重新打开文件的事件。至于如何实际实现这一点,我不知道。

我不认为 open() 会像您所建议的那样实时打开文件。

解决方案 6:

如果你有在 while 循环中运行的读取文件的代码:

f = open('/tmp/workfile', 'r')
while(1):
    line = f.readline()
    if line.find("ONE") != -1:
        print "Got it"

并且您正在从另一个程序向同一个文件写入数据(附加模式)。只要在文件中附加了“ONE”,您就会得到打印结果。您可以采取任何您想采取的行动。简而言之,您不必定期重新打开文件。

>>> f = open('/tmp/workfile', 'a')
>>> f.write("One
")
>>> f.close()
>>> f = open('/tmp/workfile', 'a')
>>> f.write("ONE
")
>>> f.close()

解决方案 7:

我有一个类似的用例,并为其编写了以下代码片段。虽然有些人可能会认为这不是最理想的做法,但这种方法可以完成工作,而且看起来很容易理解。

def reading_log_files(filename):
    with open(filename, "r") as f:
        data = f.read().splitlines()
    return data


def log_generator(filename, period=1):
    data = reading_log_files(filename)
    while True:
        time.sleep(period)
        new_data = reading_log_files(filename)
        yield new_data[len(data):]
        data = new_data


if __name__ == '__main__':
    x = log_generator(</path/to/log/file.log>)
    for lines in x:
        print(lines)
        # lines will be a list of new lines added at the end

希望你觉得这有用

解决方案 8:

这取决于你到底想用这个文件做什么。有两种潜在的用例:

  1. 从不断更新的文件(例如日志文件)中读取附加内容。

  2. 从不断被覆盖的文件中读取内容(例如 *nix 系统中的网络统计文件)

由于其他人已经详细回答了如何解决场景 #1,我想帮助那些需要场景 #2 的人。基本上,您需要在调用第 n+1次seek(0)之前使用 (或您想要读取的任何位置)将文件指针重置为 0 。read()

您的代码看起来有点像下面的函数。

def generate_network_statistics(iface='wlan0'):
    with open('/sys/class/net/' + iface + '/statistics/' + 'rx' + '_bytes', 'r') as rx:
        with open('/sys/class/net/' + iface + '/statistics/' + 'tx' + '_bytes', 'r') as tx:
            with open('/proc/uptime', 'r') as uptime:
                while True:
                    receive = int(rx.read())
                    rx.seek(0)
                    transmit = int(tx.read())
                    tx.seek(0)
                    uptime_seconds = int(uptime.read())
                    uptime.seek(0)
                    print("Receive: %i, Transmit: %i" % (receive, transmit))
                    time.sleep(1)

解决方案 9:

即使在文件末尾返回空字符串,也要保持文件句柄打开,并在休眠一段时间后再次尝试读取它。

    import time

    syslog = '/var/log/syslog'
    sleep_time_in_seconds = 1

    try:
        with open(syslog, 'r', errors='ignore') as f:
            while True:
                for line in f:
                    if line:
                        print(line.strip())
                        # do whatever you want to do on the line
                time.sleep(sleep_time_in_seconds)
    except IOError as e:
        print('Cannot open the file {}. Error: {}'.format(syslog, e))
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用