中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang如何實現文件監控

發布時間:2023-02-20 14:13:34 來源:億速云 閱讀:228 作者:iii 欄目:編程語言

本篇內容介紹了“golang如何實現文件監控”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

在golang中,可以利用fsnotify來實現文件監控。fsnotify是go語言跨平臺文件系統監控工具,實現了一個基于channel的、跨平臺的實時監聽接口;golang通過fsnotify可監控文件,并通過文件變化重啟程序。

在golang中,可以利用fsnotify來實現文件監控。

golang 通過fsnotify監控文件,并通過文件變化重啟程序。

go語言跨平臺文件系統監控工具 — fsnotify

在 linux 內核中,Inotify 是一種用于通知用戶空間程序文件系統變化的機制。它監控文件系統的變化,如文件新建、修改、刪除等,并可以將相應的事件通知給應用程序。

Inotify 既可以監控文件,也可以監控目錄。當監控目錄時,它可以同時監控目錄及目錄中的各子目錄及文件。Golang 的標準庫 syscall 實現了該機制。

為了進一步擴展和抽象, github.com/fsnotify/fsnotify 包實現了一個基于 channel 的、跨平臺的實時監聽接口。

fsnotify工具的使用

一、下載我們需要的包

go get github.com/fsnotify/fsnotify

二、使用fsnotify監控文件

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() {

   //創建一個監控對象

   watch, err := fsnotify.NewWatcher();

   if err != nil {

       log.Fatal(err);

   }

   defer watch.Close();

   //添加要監控的對象,文件或文件夾

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

   if err != nil {

       log.Fatal(err);

   }

   //我們另啟一個goroutine來處理監控對象的事件

   go func() {

       for {

           select {

           case ev := <-watch.Events:

               {

                   //判斷事件發生的類型,如下5種

                   // Create 創建

                   // Write 寫入

                   // Remove 刪除

                   // Rename 重命名

                   // Chmod 修改權限

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

                       log.Println("創建文件 : ", 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("修改權限 : ", ev.Name);

                   }

               }

           case err := <-watch.Errors:

               {

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

                   return;

               }

           }

       }

   }();

   //循環

   select {};

}

測試結果如下:

golang如何實現文件監控

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

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

修改如下:

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;

}

//監控目錄

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

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

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

       //這里判斷是否為目錄,只需監控目錄即可

       //目錄下的文件也在監控范圍內,不需要我們一個一個加

       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("監控 : ", path);

       }

       return nil;

   });

   go func() {

       for {

           select {

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

               {

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

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

                       //這里獲取新創建文件的信息,如果是目錄,則加入監控中

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

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

                           w.watch.Add(ev.Name);

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

                       }

                   }

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

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

                   }

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

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

                       //如果刪除文件是目錄,則移除監控

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

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

                           w.watch.Remove(ev.Name);

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

                       }

                   }

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

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

                       //如果重命名文件是目錄,則移除監控

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

                       //因為重命名后,go已經無法找到原文件來獲取信息了

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

                       w.watch.Remove(ev.Name);

                   }

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

                       fmt.Println("修改權限 : ", 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 {};

}

測試結果如下:

golang如何實現文件監控

經過上面的例子,我們通過fsnotify來寫一個監控配置文件,如果配置文件有修改,就重新啟動服務。

我們先寫一個可以運行的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";

)

//我們這里只是演示,配置項只設置一個

type Conf struct {

   Port int `json:port`;

}

func main() {

   //讀取文件內容

   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);

   }

   //根據配置項來監聽端口

   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("hello\n"));

       }(conn);

   }

}

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

1

> go build server.go

監控文件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";

)

//獲取進程ID

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

   //通過wmic process get name,processid | findstr server.exe獲取進程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);

   //這里通過正則把進程id提取出來

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

   pid := reg.FindString(info);

   return strconv.Atoi(pid);

}

//啟動進程

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

   attr := &os.ProcAttr{

       //files指定新進程繼承的活動文件對象

       //前三個分別為,標準輸入、標準輸出、標準錯誤輸出

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

       //新進程的環境變量

       Env: os.Environ(),

   }

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

   if err != nil {

       return err;

   }

   fmt.Println(exePath, "進程啟動");

   p.Wait();

   return nil;

}

func main() {

   //創建一個監控對象

   watch, err := fsnotify.NewWatcher();

   if err != nil {

       log.Fatal(err);

   }

   defer watch.Close();

   //添加要監控的文件

   err = watch.Add(confFilePath);

   if err != nil {

       log.Fatal(err);

   }

   //我們另啟一個goroutine來處理監控對象的事件

   go func() {

       for {

           select {

           case ev := <-watch.Events:

               {

                   //我們只需關心文件的修改

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

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

                       //查找進程

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

                       //獲取運行文件的絕對路徑

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

                       if err != nil {

                           //啟動進程

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

                       } else {

                           //找到進程,并退出

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

                           if err == nil {

                               //讓進程退出

                               process.Kill();

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

                           }

                           //啟動進程

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

                       }

                   }

               }

           case err := <-watch.Errors:

               {

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

                   return;

               }

           }

       }

   }();

   //循環

   select {};

}

我們運行fsnotify3.go文件來監控我們的配置文件

golang如何實現文件監控

通過上面的圖可以看到,當我們修改配置文件中的端口號時,會先kill掉進程,然后再啟動一個進程。

golang如何實現文件監控

“golang如何實現文件監控”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

连平县| 林芝县| 宝山区| 东港市| 三门峡市| 青神县| 桂平市| 安泽县| 兴仁县| 睢宁县| 广东省| 怀柔区| 日照市| 临夏县| 苏尼特右旗| 雷山县| 屯留县| 宿松县| 长顺县| 桃园市| 化德县| 温州市| 望江县| 黑龙江省| 桐柏县| 安乡县| 赤壁市| 怀远县| 上犹县| 朝阳市| 申扎县| 巫溪县| 五莲县| 浮山县| 北碚区| 绩溪县| 察哈| 枞阳县| 哈密市| 亳州市| 本溪|