Rumah > pembangunan bahagian belakang > Golang > Bagaimana untuk melaksanakan pemantauan fail dalam golang

Bagaimana untuk melaksanakan pemantauan fail dalam golang

青灯夜游
Lepaskan: 2023-02-20 10:18:21
asal
4728 orang telah melayarinya

Dalam golang, anda boleh menggunakan fsnotify untuk melaksanakan pemantauan fail. fsnotify ialah alat pemantauan sistem fail merentas platform dalam bahasa Go, yang melaksanakan antara muka pemantauan masa nyata berasaskan saluran, golang boleh memantau fail melalui fsnotify dan memulakan semula program melalui perubahan fail.

Bagaimana untuk melaksanakan pemantauan fail dalam golang

Persekitaran pengendalian tutorial ini: sistem Windows 10, GO versi 1.18, komputer Dell G3.

Dalam golang, anda boleh menggunakan fsnotify untuk melaksanakan pemantauan fail.

golang memantau fail melalui fsnotify dan memulakan semula program melalui perubahan fail.

Alat pemantauan sistem fail merentas platform bahasa Go - fsnotify

Dalam kernel Linux, Inotify ialah alat yang digunakan untuk memberitahu pengguna Mekanisme perubahan sistem fail program spatial. Ia memantau perubahan sistem fail, seperti penciptaan fail, pengubahsuaian, pemadaman, dsb., dan boleh memberitahu aplikasi tentang peristiwa yang sepadan.

Inotify boleh memantau kedua-dua fail dan direktori. Apabila memantau direktori, ia boleh memantau direktori dan setiap subdirektori dan fail dalam direktori pada masa yang sama. Syscall perpustakaan standard Golang melaksanakan mekanisme ini.

Untuk mengembangkan dan mengabstrakkan lagi, pakej github.com/fsnotify/fsnotify melaksanakan antara muka pemantauan masa nyata berasaskan saluran dan merentas platform.

Penggunaan alat fsnotify

1 Muat turun pakej yang kami perlukan

go get github.com/fsnotify/fsnotify
Salin selepas log masuk

2 fail

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 :=

                {

                    //判断事件发生的类型,如下5种

                    // Create 创建

                    // Write 写入

                    // Remove 删除

                    // Rename 重命名

                    // Chmod 修改权限

                     ifev.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 :=

                {

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

                    return;

                }

            }

        }

    }();

  

    //循环

    select {};

}

Keputusan ujian adalah seperti berikut:

Bagaimana untuk melaksanakan pemantauan fail dalam golang

Semua operasi kami dalam direktori tmp telah ditangkap, tetapi terdapat masalah dengan fsnotify. Ia tidak dapat membantu kami menangkap subdirektori secara rekursif . Acara operasi direktori Sun Tzu perlu dilaksanakan oleh kami sendiri.

Masalah lain ialah apabila kami mengubah suai nama folder, acara.Nama dalam fsnotify masih merupakan nama fail asal Ini memerlukan kami mengalih keluar pemantauan sebelumnya dalam acara menamakan semula, dan kemudian menambah Pemantauan baharu.

diubah suai seperti berikut:

Keputusan ujian adalah seperti berikut:

Bagaimana untuk melaksanakan pemantauan fail dalam golang

Selepas contoh di atas, kami menggunakan fsnotify untuk menulis fail konfigurasi pemantauan Jika fail konfigurasi diubah, mulakan semula perkhidmatan .

Kami mula-mula menulis program exe yang boleh dijalankan Kod server.go adalah seperti berikut:

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 :=

                {

                    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 :=

                {

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

                    return;

                }

            }

         }

    }();

}

  

func main() {

    watch, _ := fsnotify.NewWatcher()

    w := Watch{

        watch: watch,

    }

    w.watchDir("./tmp");

    select {};

}

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

        

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

    }

}

Gunakan arahan berikut untuk menyusun ke dalam fail exe

1

1

> go build server.go

> >

Kod pemantauan fsnotify3.go adalah seperti berikut:

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

102

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

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

     iferr != nil {

         returnerr;

    }

    fmt.Println(exePath, "进程启动");

    p.Wait();

     returnnil;

}

  

func main() {

    //创建一个监控对象

    watch, err := fsnotify.NewWatcher();

     iferr != nil {

        log.Fatal(err);

    }

    defer watch.Close();

    //添加要监控的文件

    err = watch.Add(confFilePath);

    if err != nil {

        log.Fatal(err);

    }

    //我们另启一个goroutine来处理监控对象的事件

    go func() {

        for {

            select {

            case ev :=

                {

                    //我们只需关心文件的修改

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

                        }

                    }

                }

             caseerr :=

                {

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

                    return;

                }

            }

        }

    }();

  🎜>

Kami menjalankan fail fsnotify3.go untuk memantau fail konfigurasi kami    //循环

    Seperti yang anda lihat daripada rajah di atas, apabila kami ubah suai fail konfigurasi Apabila menukar nombor port, proses akan dimatikan terlebih dahulu dan kemudian proses akan dimulakan. select {};

}

Pembelajaran yang disyorkan:
Tutorial Golang

Atas ialah kandungan terperinci Bagaimana untuk melaksanakan pemantauan fail dalam golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan