玩转Go和文件系统观察器的实例教程

59 阅读2分钟

让我解释一下这个想法。我想在一个文件夹中每次生成新文件时发出一条 RabbitMQ 消息。问题是,我不能修改生成文件的软件的代码。我们的想法是生成一个文件系统观察器,以发射消息。让我们开始吧。

我不是围棋专家,但围棋对于这种任务来说是很好的。你可以创建一个可执行文件,然后复制到所需的服务器中,就可以了。就可以了。

还有一个fsnotify可以监听文件系统事件。我过去曾在PHP和Python中使用fsnotify。

func main() {
	config := GetConf()
	watcher, _ = fsnotify.NewWatcher()
	defer watcher.Close()

	if err := filepath.Walk(config.Path, watchDir); err != nil {
		fmt.Println("ERROR", err)
	}
	done := make(chan bool)

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				processEvent(event, *config)
			case err := <-watcher.Errors:
				fmt.Println("ERROR", err)
			}
		}
	}()
	<-done
}

func processEvent(event fsnotify.Event, conf Conf) {
	filePath := event.Name
	fileName := filepath.Base(filePath)
	switch op := event.Op.String(); op {
	case "CREATE":
		if strings.HasSuffix(filePath, conf.Extension) {
			bytes, _ := copy(event.Name, conf.CopyTo+fileName)
			if bytes > 0 {
				emitEvent(fileName, conf)
			}
		}
	default:
		fmt.Println("Unhandled event: ", op, " on file: ", fileName)
	}
}

基本上这就是全部。我们只需要注意文件系统的事件。Fsnotify是非常低级的,当我们使用它时,我们意识到程序是如何写文件的。有些程序会创建一个临时文件,然后写下它,最后重命名该文件。有时,程序会创建一个空文件,最后写入文件。基本上是一样的,但事件是不同的。在我的例子中,我只监听 "CREATE",这对我的测试来说就足够了。

向 RabbitMQ 发出事件也很简单。在文档中得到了很好的记录。

func emitEvent(fileName string, conf Conf) {
	fmt.Println("Event on file", fileName)
	message := map[string]interface{}{
		"fileName": fileName,
	}
	bytesRepresentation, err := json.Marshal(message)
	if err != nil {
		log.Println(err)
	} else {
		emmitToRabbit(conf, bytesRepresentation)
	}
}

在这个例子中,我还想使用 YAML 文件来存储配置。只是为了学习如何在 Go 中读取 YAML 文件。

type Conf struct {
	Path        string `yaml:"path"`
	CopyTo      string `yaml:"copy_to"`
	Extension   string `yaml:"extension"`
	BrokerTopic string `yaml:"brokerTopic"`
	Broker      string `yaml:"broker"`
}

func readConf(filename string) (*Conf, error) {
	buf, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	c := &Conf{}
	err = yaml.Unmarshal(buf, c)
	if err != nil {
		return nil, fmt.Errorf("in file %q: %v", filename, err)
	}

	return c, nil
}

这就是全部。我的二进制可执行文件已经准备好了。

完整的代码在我的github上