windows下python使用fllow擴展持續讀取文件的bug

一、前言

      python通過fllow讀取文件,需求是可以監控log文件,當文件行數增加的話,就寫入到數據庫,也可以讀取歷史log文件,寫入到數據庫,因此我們通過給腳本添加參數的方式來區分是否監控log文件。

      可是當執行python的時候,明明log文件沒有新增數據,但是發現每隔60spython就會讀取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.html
os.stat() 方法用於在給定的路徑上執行一個系統 stat 的調用。

https://www.runoob.com/python/os-fstat.html
os.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下的inodelinuxinode不一樣,或者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,因爲windowslinux在某些函數調用上還是有一些差距的,建議是到linux服務器上跑一跑看看。

      因此上傳py腳本到linux,在linux上測試,發現完美實現監控日誌文件的目的,文件有更新則寫入到數據庫,無更新則持續讀取。

五、總結

      通過這篇文章的分析,對博主對打的觸動就是:windows環境果然是坑。 怪不得大佬們都是用mac電腦,天天在linux下開發呢,博主本來在windows下開發php開發的不亦樂乎,只可惜以後始終是要用到編譯型語言的,早晚都要完全在linux下開發啊。。

      行吧,解決問題的過程永遠是複雜的,查找的過程永遠是享受,通過這個問題博主又學到了很多python的知識,整體來說還是很讚的。

我是鐵柱,我爲自己代言!

end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章