一、前言
python
通过fllow
读取文件,需求是可以监控log
文件,当文件行数增加的话,就写入到数据库,也可以读取历史log
文件,写入到数据库,因此我们通过给脚本添加参数的方式来区分是否监控log
文件。
可是当执行python
的时候,明明log
文件没有新增数据,但是发现每隔60s
,python
就会读取log
文件的旧数据,并插入到数据库。这当然是不符合需求的,正常来说,log
文件无变化,fllow
不应该再去读取文件才对。
二、读取fllow源码
遇到文件就读源码,码中自有黄金屋,码中自有颜如玉。
1、fllow读取文件代码
thefile = follow.Follow(filename, False)
fllow的Follow函数如下:
class Follow(object):
def __init__(self, fname, start=False, new_file_check=60, *open_args):
可以看到参数中有个new_file_check =60,这个参数会不会就是罪魁祸首呢?
2、跟踪new_file_check 函数
def _preread(self):
if not self.f:
self._reopen(False)
return
t = time.time()
if t >= self.stat_time + self.stat_time_min: # 这部分用到了
nstat = os.stat(self.fname)
self.stat_time = t
if nstat.st_dev != self.stat.st_dev or \
nstat.st_ino != self.stat.st_ino:
# start at top of new file
self._reopen(True)
return
# should clear previous EOF condition
self.f.seek(self.pos)
代码的语意是:
当60s
之后,脚本会重新获取文件的相关属性,并对比文件的相关参数,若参数不一致则重新读取文件。
看来问题就出在了这个对比属性上,下面先看看这些属性都是什么意思
3、python的stat函数
根据if条件左边的代码格式,我们知道是用os.stat()函数的返回值进行对比的。
根据if条件右边的代码格式,我们可追踪代码,最终锁定在os.fstat()函数
手册解析:
https://www.runoob.com/python/os-stat.htmlos.stat()
方法用于在给定的路径上执行一个系统 stat
的调用。
https://www.runoob.com/python/os-fstat.htmlos.fstat()
方法用于返回文件描述符fd
的状态,类似 stat()
。Unix,Windows
上可用。
根据这个教程,我们发现
os.stat返回的结果有:
st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。 等
os.fstat返回的结果有:
st_dev: 设备信息
st_ino: 文件的i-node值
4、分析出错代码
if nstat.st_dev != self.stat.st_dev or \
nstat.st_ino != self.stat.st_ino:
# start at top of new file
self._reopen(True)
return
首先是对比: inode 驻留的设备 != 设备信息
其次是对比:inode 节点号 != 文件的i-node值
两次对比有一次不同则重新读取文件,也就是造成我们上面的bug
。
三、windows下对比inode 节点号
1、windows下打印这几个参数
print nstat.st_dev
print self.stat.st_dev
print nstat.st_ino
print self.stat.st_ino
结果:
0
0
0
73746443898579758
OK
,根据结果已经知道是文件的inode
值不同,所以造成了重新读取文件的bug
。那么为什么文件属性会发生变化呢,本地数据量又没有增加。而且既然这个文件是常用的读取文件脚本,那么怎么可能会有这明显的bug
2、os.start() 与 os.fstat()
首先明确一点,两个函数都能在windows
下正常运行。函数含义也有些相似,唯一不一样的一点就是inode
的值,关于inode
,听说最多的就是linux
文件系统的inode
了,那么会不会是windows
下的inode
和linux
的inode
不一样,或者windows
不够稳定呢
3、linux文件的inode会保持不变吗?
答案:
inode
在文件的生命周期里是不改变的,除非,你把文件删除重建。而你删除文件前100
行的动作,实际上是新建一个临时文件,把旧文件第100
行以后的东西输出到临时文件里,删掉旧文件,把临时文件的文件名重命名成旧文件的名字。也就是说你删前100
行的时候,文件已经经历了删除-重建的过程,inode
号也就改变了。
作者:北极
链接:https://www.zhihu.com/question/26127845/answer/32214159
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4、windows文件的inode会保持不变吗?
通过搜索我们发现,对于windows
来说,它有类似于inode
的概念,比如通过卷序列号/ FileId组合等来标识目录文件,但是windows
下并没有直接的inode
概念,所以在windows
下通过inode
对比文件是不稳定且不精准的。
关于windows的inode,有兴趣的可以参考:
http://zgserver.com/windowsinode.html
http://cn.voidcc.com/question/p-nvmqdzhb-vo.html
这样一对比,答案就很明显了,windows
下问题奇葩问题多,怪不得大佬们都用mac
电脑开发呢,大佬们果然诚不我欺。
四、解决方案
通过以上的分析,可以知道这个锅算是windows
的锅,怪不得py
脚本在windows
下那么多的bug
,因为windows
和linux
在某些函数调用上还是有一些差距的,建议是到linux
服务器上跑一跑看看。
因此上传py
脚本到linux
,在linux
上测试,发现完美实现监控日志文件的目的,文件有更新则写入到数据库,无更新则持续读取。
五、总结
通过这篇文章的分析,对博主对打的触动就是:windows环境果然是坑。 怪不得大佬们都是用mac
电脑,天天在linux
下开发呢,博主本来在windows
下开发php
开发的不亦乐乎,只可惜以后始终是要用到编译型语言的,早晚都要完全在linux
下开发啊。。
行吧,解决问题的过程永远是复杂的,查找的过程永远是享受,通过这个问题博主又学到了很多python
的知识,整体来说还是很赞的。
我是铁柱,我为自己代言!
end