请选择 进入手机版 | 继续访问电脑版
搜索
房产
装修
汽车
婚嫁
健康
理财
旅游
美食
跳蚤
二手房
租房
招聘
二手车
教育
茶座
我要买房
买东西
装修家居
交友
职场
生活
网购
亲子
情感
龙城车友
找美食
谈婚论嫁
美女
兴趣
八卦
宠物
手机

python实现tail -f 功能

[复制链接]
查看: 88|回复: 0

2万

主题

2万

帖子

7万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
70839
发表于 2020-1-17 02:28 | 显示全部楼层 |阅读模式
这篇文章最初是由于reboot的群里,有人去口试,笔试题有这个题,不晓得怎样做,什么思绪,就发群里大家会商
我想了一下,简单说一下我的想法吧,固然,也有很好用的pyinotify模块专门监听文件变革,不外我更想先容的,是治理的思绪,究竟作为口试官,照旧想看到一下治理题目标思绪,而且我以为这一题的难点不在于监控文件增量,而在于怎样打印最背面10行
希望大家读这篇文章前,对python根柢、处置文件和常用模块有一个简单的了解,晓得下面几个名词是啥
  1. open('a.txt')file.seekfile.telltime.sleep()
复制代码
下面思绪限于我小我常识,免不了有毛病和考虑不周的,希望大家有更好的方式提出来,我随时优化代码,题目标感受没啥太多的坑,下面让天真绚丽的蜗牛教大家用python的思绪
怎样用python实现
实在思绪也不难啦

  • 翻开这个文件,指针移到最初
  • 每隔一秒就尝试readline一下,有内容就打印出来,没内容就sleep
  • 大要就是这么个意义
监听文件
思绪以下:

  • 用open翻开文件
  • 用seek文件指针,给大爷把跳到文件最背面
  • while True举行循环
    持续不停的readline,假如能读到内容,打印出来即可
代码呼之欲出
  1. with open('test.txt') as f:    f.seek(0,2)    while True:        last_pos = f.tell()        line = f.readline()        if line:            print line
复制代码
代码说明

  • seek第二个参数2,意义就是从文件末端处起头seek,更标准的写法操纵os模块下面的SEEK_END,可读性更好
  • 只写出了简单的逻辑,代码简单粗鲁,假如这个题目是10分的话,最多也就拿4分吧,不能再多了
优化点

  • print有缺点,每次都是新的一行,换成sys.stdout.write(line)更和谐
  • 文件名传参,不能写死
  • 间接打印可以当做默许活动,具体要做什么,可以写成函数处置,这样我们便可以把新行做其他处置,比如展现在欣赏器里
  • 加上容错处置,比如文件不存在会报错
  • while True不停都文件,比力耗性能,每读一次,间隔一秒比力靠谱
    挪用time.sleep(1)
  • 用类来机关代码
实例代码以下
  1. #!/usr/bin/env python# -*- coding:utf-8 -*-import sysimport timeclass Tail():    def __init__(self,file_name,callback=sys.stdout.write):        self.file_name = file_name        self.callback = callback    def follow(self):        try:            with open(self.file_name) as f:                f.seek(0,2)                while True:                    line = f.readline()                    if line:                        self.callback(line)                    time.sleep(1)        except Exception,e:            print '翻开文件失利,囧,看看文件能否是不存在,大要权限有题目'            print e
复制代码
操纵方式:
  1. # 操纵默许的sys.stdout.write打印到屏幕py_tail = Tail('test.txt')py_tail.follow()# 自己界说处置函数def test_tail(line):    print 'xx'+line+'xx'py_tail1 = Tail('test.txt', test_tail)py_tail1.follow()
复制代码
咦 等等,tail -f 默许还会打印最初10行,这个似乎才是这个题目标难点地址,众所周知,python里读文件指针,只能移动到牢固位置,不能判定是哪一行,囧,先实现简单的,渐渐增强吧
默许打印最初10行
现在这个代码,大要能拿6分啦,我们还有一个功用没做,那就是打印最初n行,默许是10行,现在把这个功用加上,加一个函数就行啦
文件小的时辰
我们晓得,readlines可以获得全数内容,而且分行,代码呼之欲出,获得list最初10行很简单有么有,切片妥妥的
  1. # 演示代码,说明焦点逻辑,完整代码鄙人面last_lines = f.readlines()[-10:]for line in last_lines:    self.callback(line)
复制代码
此时代码酿成这样了
  1. import sysimport timeclass Tail():    def __init__(self,file_name,callback=sys.stdout.write):        self.file_name = file_name        self.callback = callback    def follow(self,n=10):        try:            with open(self.file_name) as f:                self._file = f                self.showLastLine(n)                self._file.seek(0,2)                while True:                    line = self._file.readline()                    if line:                        self.callback(line)        except Exception,e:            print '翻开文件失利,囧,看看文件能否是不存在,大要权限有题目'            print e    def showLastLine(self, n):        last_lines = self._file.readlines()[-10:]        for line in last_lines:            self.callback(line)
复制代码
更进一步:大的日志怎样办
此时代码有7分时很随意啦,可是假如文件出格大呢,出格是日志文件,很轻易几个G,我们只需要最初几行,全数读出来内存受不了,所以我们要继续优化showLastLine函数,我以为这才是这题的难点地址
大要的思绪以下

  • 我先估量日志一行大如果100个字符,留意,我只是估量一个大要,多了也没关系,我们只是需要一个初始值,背面会批改
  • 我要读十行,所以一路头就seek到离末端1000的位置seek(-1000,2),把最初1000个字符读出来,然后有一个判定
  • 假如这1000个字符长度大于文件长度,不用管了 属于级别1的情况,间接read然后split
  • 假如1000个字符里面的换行符大于10,说明1000个字符里,大于10行,那也好办,处置思绪类似级别1,间接split取背面十个
  • 题目就在于 假如小于10怎样处置
    比如1000个里,只要四个换行符,说明一行大如果1000/4=250个字符,我们还缺6行,所以我们再读250*5=1500,一共有2500的大要比力靠谱,然后在对2500个字符举行类似的逻辑判定,直到读出的字符里,换行符大于10,读取竣事
逻辑清楚今后,代码就呼之欲出啦
加上表白的版本
  1. #!/usr/bin/env python# -*- coding:utf-8 -*-import sysimport timeclass Tail():    def __init__(self,file_name,callback=sys.stdout.write):        self.file_name = file_name        self.callback = callback    def follow(self,n=10):        try:            # 翻开文件            with open(self.file_name) as f:                self._file = f                self._file.seek(0,2)                # 存储文件的字符长度                self.file_length = self._file.tell()                # 打印最初10行                self.showLastLine(n)                # 持续读文件 打印增量                while True:                    line = self._file.readline()                    if line:                        self.callback(line)                    time.sleep(1)        except Exception,e:            print '翻开文件失利,囧,看看文件能否是不存在,大要权限有题目'            print e    def showLastLine(self, n):        # 一行大要100个吧 这个数改成1大要1000都行        len_line = 100        # n默许是10,也可以follow的参数传进来        read_len = len_line*n        # 用last_lines存储最初要处置的内容        while True:            # 假如要读取的1000个字符,大于之前存储的文件长度            # 读完文件,间接break            if read_len>self.file_length:                self._file.seek(0)                last_lines = self._file.read().split('\n')[-n:]                break            # 先读1000个 然后判定1000个字符里换行符的数目            self._file.seek(-read_len, 2)            last_words = self._file.read(read_len)            # count是换行符的数目            count = last_words.count('\n')                        if count>=n:                # 换行符数目大于10 很益处置,间接读取                last_lines = last_words.split('\n')[-n:]                break            # 换行符不够10个            else:                # break                #不够十行                # 假如一个换行符也没有,那末我们就以为一行大如果100个                if count==0:                    len_perline = read_len                # 倘使有4个换行符,我们以为每行大要有250个字符                else:                    len_perline = read_len/count                # 要读取的长度变成2500,继续重新判定                read_len = len_perline * n        for line in last_lines:            self.callback(line+'\n')if __name__ == '__main__':    py_tail = Tail('test.txt')    py_tail.follow(20)
复制代码
结果以下,终究可以打印最初几行了,大家可以试一下,不管日志每行只要1个,照旧每行有300个字符,都是可以打印最初10行的
能做到这个地步,一样平常的口试官就间接被你搞定了,这个代码大要8分吧,假如还想再进一步,还有一些可以优化的地方,代码放github上了,有爱好的可以拿去研讨
待优化:留给大家作为扩大

  • 假如你tail -f的进程中,日志被备份清空大要切割了,怎样处置
    实在很简单,你保护一个指针位置,假以下次循环发现文件指针位置变了,从最新的指针位置起头读就行
  • 具体每种毛病的典范
    我这里只是简单的try 可以写个函数,把文件不存在,文件没权限这些报错信息分隔
  • 性能小优化,比如我第一次读了1000,只要4行,我大要估量每行250个字符,整体需要2500行,下次没必要间接读2500个,而是读1500行和之前1000行拼起来即可
最初大杀器 假如写出来这个,底子口试官会间接
打死你
  1. import osdef tail(file_name):    os.system('tail -f '+file_name)tail('log.log')
复制代码
免责声明:假如加害了您的权益,请联系站长,我们会实时删除侵权内容,感谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2006-2014 淄博新闻网-淄博日报 淄博晚报 淄博财经新报 掌中淄博 淄博专业新闻资讯发布网站 版权所有 法律顾问:高律师 客服电话:0791-88289918
技术支持:迪恩网络科技公司  Powered by Discuz! X3.2
快速回复 返回顶部 返回列表