欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          在golang中,可以利用fsnotify來實(shí)現(xiàn)文件監(jiān)控。fsnotify是go語言跨平臺文件系統(tǒng)監(jiān)控工具,實(shí)現(xiàn)了一個(gè)基于channel的、跨平臺的實(shí)時(shí)監(jiān)聽接口;golang通過fsnotify可監(jiān)控文件,并通過文件變化重啟程序。

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          本教程操作環(huán)境:windows10系統(tǒng)、GO 1.18版本、Dell G3電腦。

          在golang中,可以利用fsnotify來實(shí)現(xiàn)文件監(jiān)控。

          golang 通過fsnotify監(jiān)控文件,并通過文件變化重啟程序。

          go語言跨平臺文件系統(tǒng)監(jiān)控工具 — fsnotify

          在 linux 內(nèi)核中,Inotify 是一種用于通知用戶空間程序文件系統(tǒng)變化的機(jī)制。它監(jiān)控文件系統(tǒng)的變化,如文件新建、修改、刪除等,并可以將相應(yīng)的事件通知給應(yīng)用程序。

          Inotify 既可以監(jiān)控文件,也可以監(jiān)控目錄。當(dāng)監(jiān)控目錄時(shí),它可以同時(shí)監(jiān)控目錄及目錄中的各子目錄及文件。Golang 的標(biāo)準(zhǔn)庫 syscall 實(shí)現(xiàn)了該機(jī)制。

          為了進(jìn)一步擴(kuò)展和抽象, github.com/fsnotify/fsnotify 包實(shí)現(xiàn)了一個(gè)基于 channel 的、跨平臺的實(shí)時(shí)監(jiān)聽接口。

          fsnotify工具的使用

          一、下載我們需要的包

          go get github.com/fsnotify/fsnotify
          登錄后復(fù)制

          二、使用fsnotify監(jiān)控文件

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          package main;

          import (

          "github.com/fsnotify/fsnotify"

          "log"

          "fmt"

          )

          func main() {

          //創(chuàng)建一個(gè)監(jiān)控對象

          watch, err := fsnotify.NewWatcher();

          if err != nil {

          log.Fatal(err);

          }

          defer watch.Close();

          //添加要監(jiān)控的對象,文件或文件夾

          err = watch.Add("./tmp");

          if err != nil {

          log.Fatal(err);

          }

          //我們另啟一個(gè)goroutine來處理監(jiān)控對象的事件

          go func() {

          for {

          select {

          case ev := <-watch.Events:

          {

          //判斷事件發(fā)生的類型,如下5種

          // Create 創(chuàng)建

          // Write 寫入

          // Remove 刪除

          // Rename 重命名

          // Chmod 修改權(quán)限

          if ev.Op&fsnotify.Create == fsnotify.Create {

          log.Println("創(chuàng)建文件 : ", ev.Name);

          }

          if ev.Op&fsnotify.Write == fsnotify.Write {

          log.Println("寫入文件 : ", ev.Name);

          }

          if ev.Op&fsnotify.Remove == fsnotify.Remove {

          log.Println("刪除文件 : ", ev.Name);

          }

          if ev.Op&fsnotify.Rename == fsnotify.Rename {

          log.Println("重命名文件 : ", ev.Name);

          }

          if ev.Op&fsnotify.Chmod == fsnotify.Chmod {

          log.Println("修改權(quán)限 : ", ev.Name);

          }

          }

          case err := <-watch.Errors:

          {

          log.Println("error : ", err);

          return;

          }

          }

          }

          }();

          //循環(huán)

          select {};

          }

          測試結(jié)果如下:

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          我們在tmp目錄下的操作都被捕捉到了,但是fsnotify有一個(gè)問題,它無法遞歸的幫我們捕捉子目錄、孫子目錄的操作事件,這需要我們自已來實(shí)現(xiàn)。

          還有一個(gè)問題就是當(dāng)們修改文件夾名稱時(shí),fsnotify中event.Name仍然是原來的文件名,這就需要我們在重命名事件中,先移除之前的監(jiān)控,然后添加新的監(jiān)控。

          修改如下:

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          61

          62

          63

          64

          65

          66

          67

          68

          69

          70

          71

          72

          73

          74

          75

          76

          77

          78

          79

          80

          81

          82

          83

          84

          85

          86

          87

          88

          package main;

          import (

          "github.com/fsnotify/fsnotify"

          "fmt"

          "path/filepath"

          "os"

          )

          type Watch struct {

          watch *fsnotify.Watcher;

          }

          //監(jiān)控目錄

          func (w *Watch) watchDir(dir string) {

          //通過Walk來遍歷目錄下的所有子目錄

          filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {

          //這里判斷是否為目錄,只需監(jiān)控目錄即可

          //目錄下的文件也在監(jiān)控范圍內(nèi),不需要我們一個(gè)一個(gè)加

          if info.IsDir() {

          path, err := filepath.Abs(path);

          if err != nil {

          return err;

          }

          err = w.watch.Add(path);

          if err != nil {

          return err;

          }

          fmt.Println("監(jiān)控 : ", path);

          }

          return nil;

          });

          go func() {

          for {

          select {

          case ev := <-w.watch.Events:

          {

          if ev.Op&fsnotify.Create == fsnotify.Create {

          fmt.Println("創(chuàng)建文件 : ", ev.Name);

          //這里獲取新創(chuàng)建文件的信息,如果是目錄,則加入監(jiān)控中

          fi, err := os.Stat(ev.Name);

          if err == nil && fi.IsDir() {

          w.watch.Add(ev.Name);

          fmt.Println("添加監(jiān)控 : ", ev.Name);

          }

          }

          if ev.Op&fsnotify.Write == fsnotify.Write {

          fmt.Println("寫入文件 : ", ev.Name);

          }

          if ev.Op&fsnotify.Remove == fsnotify.Remove {

          fmt.Println("刪除文件 : ", ev.Name);

          //如果刪除文件是目錄,則移除監(jiān)控

          fi, err := os.Stat(ev.Name);

          if err == nil && fi.IsDir() {

          w.watch.Remove(ev.Name);

          fmt.Println("刪除監(jiān)控 : ", ev.Name);

          }

          }

          if ev.Op&fsnotify.Rename == fsnotify.Rename {

          fmt.Println("重命名文件 : ", ev.Name);

          //如果重命名文件是目錄,則移除監(jiān)控

          //注意這里無法使用os.Stat來判斷是否是目錄了

          //因?yàn)橹孛螅琯o已經(jīng)無法找到原文件來獲取信息了

          //所以這里就簡單粗爆的直接remove好了

          w.watch.Remove(ev.Name);

          }

          if ev.Op&fsnotify.Chmod == fsnotify.Chmod {

          fmt.Println("修改權(quán)限 : ", ev.Name);

          }

          }

          case err := <-w.watch.Errors:

          {

          fmt.Println("error : ", err);

          return;

          }

          }

          }

          }();

          }

          func main() {

          watch, _ := fsnotify.NewWatcher()

          w := Watch{

          watch: watch,

          }

          w.watchDir("./tmp");

          select {};

          }

          測試結(jié)果如下:

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          經(jīng)過上面的例子,我們通過fsnotify來寫一個(gè)監(jiān)控配置文件,如果配置文件有修改,就重新啟動(dòng)服務(wù)。

          我們先寫一個(gè)可以運(yùn)行的exe程序,server.go代碼如下:

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          package main;

          import (

          "io/ioutil"

          "log"

          "encoding/json"

          "net"

          "fmt"

          "os"

          "os/signal"

          )

          const (

          confFilePath = "./conf/conf.json";

          )

          //我們這里只是演示,配置項(xiàng)只設(shè)置一個(gè)

          type Conf struct {

          Port int `json:port`;

          }

          func main() {

          //讀取文件內(nèi)容

          data, err := ioutil.ReadFile(confFilePath);

          if err != nil {

          log.Fatal(err);

          }

          var c Conf;

          //解析配置文件

          err = json.Unmarshal(data, &c);

          if err != nil {

          log.Fatal(err);

          }

          //根據(jù)配置項(xiàng)來監(jiān)聽端口

          lis, err := net.Listen("tcp", fmt.Sprintf(":%d", c.Port));

          if err != nil {

          log.Fatal(err);

          }

          log.Println("server start");

          go func() {

          ch := make(chan os.Signal);

          //獲取程序退出信號

          signal.Notify(ch, os.Interrupt, os.Kill);

          <-ch;

          log.Println("server exit");

          os.Exit(1);

          }();

          for {

          conn, err := lis.Accept();

          if err != nil {

          continue;

          }

          go func(conn net.Conn) {

          defer conn.Close();

          conn.Write([]byte("hellon"));

          }(conn);

          }

          }

          使用如下命令,編譯成exe文件

          1

          > go build server.go

          監(jiān)控文件fsnotify3.go代碼如下:

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          18

          19

          20

          21

          22

          23

          24

          25

          26

          27

          28

          29

          30

          31

          32

          33

          34

          35

          36

          37

          38

          39

          40

          41

          42

          43

          44

          45

          46

          47

          48

          49

          50

          51

          52

          53

          54

          55

          56

          57

          58

          59

          60

          61

          62

          63

          64

          65

          66

          67

          68

          69

          70

          71

          72

          73

          74

          75

          76

          77

          78

          79

          80

          81

          82

          83

          84

          85

          86

          87

          88

          89

          90

          91

          92

          93

          94

          95

          96

          97

          98

          99

          100

          101

          102

          103

          104

          105

          106

          107

          108

          109

          110

          111

          package main;

          import (

          "github.com/fsnotify/fsnotify"

          "log"

          "fmt"

          "os/exec"

          "regexp"

          "strconv"

          "bytes"

          "errors"

          "os"

          "path/filepath"

          )

          const (

          confFilePath = "./conf";

          )

          //獲取進(jìn)程ID

          func getPid(processName string) (int, error) {

          //通過wmic process get name,processid | findstr server.exe獲取進(jìn)程ID

          buf := bytes.Buffer{};

          cmd := exec.Command("wmic", "process", "get", "name,processid");

          cmd.Stdout = &buf;

          cmd.Run();

          cmd2 := exec.Command("findstr", processName);

          cmd2.Stdin = &buf;

          data, _ := cmd2.CombinedOutput();

          if len(data) == 0 {

          return -1, errors.New("not find");

          }

          info := string(data);

          //這里通過正則把進(jìn)程id提取出來

          reg := regexp.MustCompile(`[0-9]+`);

          pid := reg.FindString(info);

          return strconv.Atoi(pid);

          }

          //啟動(dòng)進(jìn)程

          func startProcess(exePath string, args []string) error {

          attr := &os.ProcAttr{

          //files指定新進(jìn)程繼承的活動(dòng)文件對象

          //前三個(gè)分別為,標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤輸出

          Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},

          //新進(jìn)程的環(huán)境變量

          Env: os.Environ(),

          }

          p, err := os.StartProcess(exePath, args, attr);

          if err != nil {

          return err;

          }

          fmt.Println(exePath, "進(jìn)程啟動(dòng)");

          p.Wait();

          return nil;

          }

          func main() {

          //創(chuàng)建一個(gè)監(jiān)控對象

          watch, err := fsnotify.NewWatcher();

          if err != nil {

          log.Fatal(err);

          }

          defer watch.Close();

          //添加要監(jiān)控的文件

          err = watch.Add(confFilePath);

          if err != nil {

          log.Fatal(err);

          }

          //我們另啟一個(gè)goroutine來處理監(jiān)控對象的事件

          go func() {

          for {

          select {

          case ev := <-watch.Events:

          {

          //我們只需關(guān)心文件的修改

          if ev.Op&fsnotify.Write == fsnotify.Write {

          fmt.Println(ev.Name, "文件寫入");

          //查找進(jìn)程

          pid, err := getPid("server.exe");

          //獲取運(yùn)行文件的絕對路徑

          exePath, _ := filepath.Abs("./server.exe")

          if err != nil {

          //啟動(dòng)進(jìn)程

          go startProcess(exePath, []string{});

          } else {

          //找到進(jìn)程,并退出

          process, err := os.FindProcess(pid);

          if err == nil {

          //讓進(jìn)程退出

          process.Kill();

          fmt.Println(exePath, "進(jìn)程退出");

          }

          //啟動(dòng)進(jìn)程

          go startProcess(exePath, []string{});

          }

          }

          }

          case err := <-watch.Errors:

          {

          fmt.Println("error : ", err);

          return;

          }

          }

          }

          }();

          //循環(huán)

          select {};

          }

          我們運(yùn)行fsnotify3.go文件來監(jiān)控我們的配置文件

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          通過上面的圖可以看到,當(dāng)我們修改配置文件中的端口號時(shí),會(huì)先kill掉進(jìn)程,然后再啟動(dòng)一個(gè)進(jìn)程。

          golang怎么實(shí)現(xiàn)文件監(jiān)控

          推薦學(xué)習(xí):Golang教程

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號