Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python:连续读取文件,即使它已经被日志旋转_Python_File - Fatal编程技术网

python:连续读取文件,即使它已经被日志旋转

python:连续读取文件,即使它已经被日志旋转,python,file,Python,File,我有一个简单的python脚本,在这里我可以连续读取日志文件(与tail-f相同) 在日志文件被logrotate旋转后,如何确保我仍然可以读取日志文件 i、 e.我需要做与tail-F相同的事情 我使用的是python2.7您可以跟踪文件中的位置,并在需要阅读时重新打开它。当日志文件旋转时,您会注意到文件变小了,并且由于重新打开,您也会处理任何取消链接的操作 import time cur = 0 while True: try: with open('myfile'

我有一个简单的python脚本,在这里我可以连续读取日志文件(与
tail-f
相同)

在日志文件被logrotate旋转后,如何确保我仍然可以读取日志文件

i、 e.我需要做与
tail-F
相同的事情


我使用的是
python2.7

您可以跟踪文件中的位置,并在需要阅读时重新打开它。当日志文件旋转时,您会注意到文件变小了,并且由于重新打开,您也会处理任何取消链接的操作

import time

cur = 0
while True:
    try:
        with open('myfile') as f:
            f.seek(0,2)
            if f.tell() < cur:
                f.seek(0,0)
            else:
                f.seek(cur,0)
            for line in f:
                print line.strip()
            cur = f.tell()
    except IOError, e:
        pass
    time.sleep(1)
导入时间
cur=0
尽管如此:
尝试:
将open('myfile')作为f:
f、 搜索(0,2)
如果f.tell()

此示例隐藏了诸如“找不到文件”之类的错误,因为我不确定logrotate的详细信息,例如文件不可用的小时间段。

只要您只计划在Unix上执行此操作,最可靠的方法可能是进行检查,以便打开的文件仍然与名称相同,当情况不再如此时,重新打开它。您可以在
st_ino
字段中从
os.stat
os.fstat
获取文件的i号

它可能是这样的:

import os, sys, time

name = "logfile"
current = open(name, "r")
curino = os.fstat(current.fileno()).st_ino
while True:
    while True:
        buf = current.read(1024)
        if buf == "":
            break
        sys.stdout.write(buf)
    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)

我怀疑这在Windows上是否有效,但既然您是从
尾部
的角度讲的,我猜这不是问题。:)

多亏了@tdelaney和@Dolda2000的回答,我最终得到了以下结果。它应该可以在Linux和Windows上工作,还可以处理logrotate的
copyruncate
create
选项(分别是复制然后将大小截断为0,移动然后重新创建文件)


使用
copyruncate
选项时的一个限制是,如果在睡眠时将行追加到文件中,并且在唤醒之前发生旋转,最后的行将“丢失”(它们仍将位于现在的“旧”日志文件中,但我看不到一个合适的方法“跟随”该文件完成读取)。此限制与“移动并创建”
create
选项无关,因为
f
描述符仍将指向重命名的文件,因此在关闭并再次打开描述符之前,最后一行将被读取。

可能不是重复的,但肯定是相关的:有一个配方可以做到这一点。不过我自己还没试过。非常感谢。不过,我想知道是否有更好/更优雅的解决方案。例如,有没有办法检查我的文件描述符
f
是否仍然指向文件
file.log
?我猜想,在文件被日志旋转之后,文件描述符仍然会指向旧文件,而不是新的
文件。log
这对于文件操作来说是相当优雅的。问题是,如果文件保持打开状态,其文件描述符将继续指向已旋转的文件,而不是新文件。如果不重新检查原始文件名,就无法判断它是否已过期。另一种方法是使用inotify,它可以让您随时了解文件操作。这更复杂,但也是一个很好的方法。要不要详细说明一下否决票:)?我很乐意更新答案。
import os, sys, time

name = "logfile"
current = open(name, "r")
curino = os.fstat(current.fileno()).st_ino
while True:
    while True:
        buf = current.read(1024)
        if buf == "":
            break
        sys.stdout.write(buf)
    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)
file_name = 'my_log_file'
seek_end = True
while True:  # handle moved/truncated files by allowing to reopen
    with open(file_name) as f:
        if seek_end:  # reopened files must not seek end
            f.seek(0, 2)
        while True:  # line reading loop
            line = f.readline()
            if not line:
                try:
                    if f.tell() > os.path.getsize(file_name):
                        # rotation occurred (copytruncate/create)
                        f.close()
                        seek_end = False
                        break
                except FileNotFoundError:
                    # rotation occurred but new file still not created
                    pass  # wait 1 second and retry
                time.sleep(1)
            do_stuff_with(line)