<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺析gowatch監(jiān)聽文件變動實現(xiàn)原理

          共 2502字,需瀏覽 6分鐘

           ·

          2021-11-30 23:42

          剛開始接觸go時,發(fā)現(xiàn)go程序和php程序的其中一個不同是php是解釋性語言,go是編譯型語言,即每次在有程序改動后,需要重新運行 go run或go build進(jìn)行重新編譯,更改才能生效,實則不便。于是乎在網(wǎng)絡(luò)上搜索發(fā)現(xiàn)了gowatch這個包,該包可通過監(jiān)聽當(dāng)前目錄下相關(guān)文件的變動,對go文件實時編譯,提高研發(fā)效率。那gowatch又是如何做到監(jiān)聽文件變化的呢?

          通過閱讀源碼我們發(fā)現(xiàn),在linux內(nèi)核中,有一種用于通知用戶空間程序文件系統(tǒng)變化的機制—Inotify。它監(jiān)控文件系統(tǒng),并且及時向?qū)iT的應(yīng)用程序發(fā)出相關(guān)的事件警告,比如刪除、讀、寫和卸載操作等。您還可以跟蹤活動的源頭和目標(biāo)等細(xì)節(jié)。Golang的標(biāo)準(zhǔn)庫syscall實現(xiàn)了該機制。為進(jìn)一步擴(kuò)展,實現(xiàn)了fsnotify包實現(xiàn)了一個基于通道的、跨平臺的實時監(jiān)聽接口。如下圖:



          根據(jù)上圖可知,監(jiān)聽文件的變化主要依賴于linux內(nèi)核的INotify接口機制。Go的標(biāo)準(zhǔn)庫中對其做了實現(xiàn)。而fsnotify package的主要作用就是將進(jìn)一步封裝成watcher結(jié)構(gòu)體和事件類型結(jié)構(gòu)體的封裝,從而實現(xiàn)事件的判斷以及目錄的監(jiān)聽。下面看下 fsnotify package中對watcher的封裝。

          type Watcher struct {
          mu sync.Mutex // Map access
          fd int // File descriptor (as returned by the inotify_init() syscall)
          watches map[string]*watch // Map of inotify watches (key: path)
          fsnFlags map[string]uint32 // Map of watched files to flags used for filter
          fsnmut sync.Mutex // Protects access to fsnFlags.
          paths map[int]string // Map of watched paths (key: watch descriptor)
          Error chan error // Errors are sent on this channel
          internalEvent chan *FileEvent // Events are queued on this channel
          Event chan *FileEvent // Events are returned on this channel
          done chan bool // Channel for sending a "quit message" to the reader goroutine
          isClosed bool // Set to true when Close() is first called
          }


          linux內(nèi)核Inotify接口簡介


          inotify中主要涉及3個接口。分別是inotify_init, inotify_add_watch,read。具體如下:

          接口名作用
          int fd = inotify_init()創(chuàng)建inotify實例,返回對應(yīng)的文件描述符
          inotify_add_watch (fd, path, mask)注冊被監(jiān)視目錄或文件的事件
          read (fd, buf, BUF_LEN)讀取監(jiān)聽到的文件事件?


          Inotify可以監(jiān)聽的文件系統(tǒng)事件列表:

          事件名稱事件說明

          IN_ACCESS

          文件被訪問

          IN_MODIFY

          文件被 write

          IN_CLOSE_WRITE

          可寫文件被 close

          IN_OPEN

          文件被 open

          IN_MOVED_TO

          文件被移來,如 mv、cp

          IN_CREATE

          創(chuàng)建新文件

          IN_DELETE

          文件被刪除,如 rm

          IN_DELETE_SELF

          自刪除,即一個可執(zhí)行文件在執(zhí)行時刪除自己
          IN_MOVE_SELF自移動,即一個可執(zhí)行文件在執(zhí)行時移動自己
          IN_ATTRIB文件屬性被修改,如 chmod、chown、touch 等
          IN_CLOSE_NOWRITE不可寫文件被 close
          IN_MOVED_FROM文件被移走,如 mv
          IN_UNMOUNT宿主文件系統(tǒng)被 umount
          IN_CLOSE文件被關(guān)閉,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
          IN_MOVE文件被移動,等同于(IN_MOVED_FROM | IN_MOVED_TO)


          示例應(yīng)用


          接下來是一個簡易的示例應(yīng)用,具體的應(yīng)用實例可參考github.com/silenceper/gowatch包源代碼?。


          主要邏輯如下:

          1. 初始化watcher對象

          2. 將文件或目錄加入到watcher監(jiān)控對象的隊列

          3. 啟動監(jiān)聽協(xié)程,實時獲取文件對象事件


          package main
          import (
          "fmt"
          "github.com/howeyc/fsnotify" "runtime")

          var exit chan bool
          func main() {????//1、初始化監(jiān)控對象watcher watcher, err := fsnotify.NewWatcher()
          if err != nil {
          fmt.Printf("Fail to create new Watcher[ %s ]\n", err) }
          ????//3、啟動監(jiān)聽文件對象事件協(xié)程 go func() { fmt.Println("開始監(jiān)聽文件變化") for { select { case e := <-watcher.Event: // 這里添加根據(jù)文件變化的業(yè)務(wù)邏輯 fmt.Printf("監(jiān)聽到文件 - %s變化\n", e.Name) if e.IsCreate() { fmt.Println("監(jiān)聽到文件創(chuàng)建事件") } if e.IsDelete() { fmt.Println("監(jiān)聽到文件刪除事件") } if e.IsModify() { fmt.Println("監(jiān)聽到文件修改事件") } if e.IsRename() { fmt.Println("監(jiān)聽到文件重命名事件") } if e.IsAttrib() { fmt.Println("監(jiān)聽到文件屬性修改事件") }
          fmt.Println("根據(jù)文件變化開始執(zhí)行業(yè)務(wù)邏輯") case err := <-watcher.Error:
          fmt.Printf(" %s\n", err.Error()) } } }()????//?2、將需要監(jiān)聽的文件加入到watcher的監(jiān)聽隊列中 paths := []string{"config.yml"}
          for _, path := range paths {
          err = watcher.Watch(path) //將文件加入監(jiān)聽
          if err != nil {
          fmt.Sprintf("Fail to watch directory[ %s ]\n", err) } }
          <-exit runtime.Goexit()}


          推薦閱讀


          福利

          我為大家整理了一份從入門到進(jìn)階的Go學(xué)習(xí)資料禮包,包含學(xué)習(xí)建議:入門看什么,進(jìn)階看什么。關(guān)注公眾號 「polarisxu」,回復(fù)?ebook?獲?。贿€可以回復(fù)「進(jìn)群」,和數(shù)萬 Gopher 交流學(xué)習(xí)。

          瀏覽 43
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲网址中文字幕 | A片免费观看在线 | 国产精品人妻无码久久久郑州天气网 | 日本成人黄色网址 | 天天上天天干天天日 |