尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Go管理配置文件+实时监控文件变更

Go管理配置文件+实时监控文件变更
📅 发布时间:2026/6/19 8:08:41

需求:现在的配置文件的文件格式为

/data/版本号1/xx.jsonyy.json版本号2/xx.jsonyy.json
package utilimport ("app01/config""encoding/json""fmt""os""path/filepath""strings""sync""time""github.com/fsnotify/fsnotify"
)// Package configmanager 提供通用的JSON配置文件管理功能
// 支持多种JSON格式,多版本管理,内存缓存,线程安全// ConfigManager 通用配置管理器(支持多版本)
type ConfigManager struct {versions       map[string]map[string]interface{} // version -> fileName -> config datamu             sync.RWMutex                      // 读写锁,保护versionswatcher        *fsnotify.Watcher                 // 文件监控器watchDone      chan struct{}                     // 用于停止监控的通道debounceTimers sync.Map                          // 用于防抖的定时器 map[filePath]*time.Timer
}// 全局单例
var (globalConfigManager *ConfigManagerconfigOnce          sync.Once
)// GetConfigManager 获取全局配置管理器单例
func GetConfigManager() *ConfigManager {configOnce.Do(func() {// 创建文件监控器watcher, err := fsnotify.NewWatcher()if err != nil {fmt.Printf("创建文件监控器失败: %v\n", err)}globalConfigManager = &ConfigManager{versions:  make(map[string]map[string]interface{}),watcher:   watcher,watchDone: make(chan struct{}),}// 启动监控协程if watcher != nil {go globalConfigManager.startWatchLoop()}})return globalConfigManager
}// WatchConfigFiles 监控指定版本的配置文件变更
func (cm *ConfigManager) WatchConfigFiles(version string, jsonFiles []string) error {if cm.watcher == nil {return fmt.Errorf("文件监控器未初始化")}for _, jsonFile := range jsonFiles {filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)// 添加文件到监控器if err := cm.watcher.Add(filePath); err != nil {Log.Error(fmt.Sprintf("添加监控文件 %s 失败: %v", filePath, err))return fmt.Errorf("添加监控文件 %s 失败: %v", filePath, err)}}return nil
}// StopWatch 停止文件监控
func (cm *ConfigManager) StopWatch() {if cm.watcher != nil {close(cm.watchDone)err := cm.watcher.Close()if err != nil {return}cm.watcher = nil}
}// startWatchLoop 启动监控事件循环
func (cm *ConfigManager) startWatchLoop() {for {select {case event, ok := <-cm.watcher.Events:if !ok {return}// 只处理写入事件if event.Op&fsnotify.Write == fsnotify.Write {filePath := event.Name// 防抖处理: 500ms内重复事件只执行最后一次if timer, ok := cm.debounceTimers.Load(filePath); ok {timer.(*time.Timer).Stop()}// 创建新的定时器timer := time.AfterFunc(500*time.Millisecond, func() {cm.debounceTimers.Delete(filePath)// 解析版本和文件名relPath, err := filepath.Rel(config.AppConfig.App.ConfigDir, event.Name)if err != nil {return}// 分割版本和文件名 (data/version/file.json)parts := strings.Split(relPath, string(filepath.Separator))if len(parts) < 2 {Log.Error(fmt.Sprintf("无效的配置文件路径: %s\n", event.Name))return}version := parts[0]jsonFile := strings.Join(parts[1:], string(filepath.Separator))// 执行重新加载if err := cm.ReloadConfigWithVersion(version, jsonFile); err != nil {Log.Error(fmt.Sprintf("重新加载配置文件失败: %v\n", err))}})cm.debounceTimers.Store(filePath, timer)}case err, ok := <-cm.watcher.Errors:if !ok {return}Log.Error(fmt.Sprintf("监控器错误: %v\n", err))case <-cm.watchDone:return}}
}// LoadConfigWithVersion 从文件加载JSON配置到指定版本
func (cm *ConfigManager) LoadConfigWithVersion(version, jsonFile string) error {cm.mu.Lock()defer cm.mu.Unlock()// 初始化版本映射if cm.versions[version] == nil {cm.versions[version] = make(map[string]interface{})}// 如果已经加载过,直接返回if _, exists := cm.versions[version][jsonFile]; exists {return nil}filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)data, err := os.ReadFile(filePath)if err != nil {return fmt.Errorf("读取JSON文件 %s 失败: %v", filePath, err)}var configStruct interface{}err = json.Unmarshal(data, &configStruct)if err != nil {return fmt.Errorf("解析JSON失败: %v", err)}cm.versions[version][jsonFile] = configStructreturn nil
}// LoadConfigs 批量加载多个配置文件(默认版本)
// LoadConfigsWithVersion 批量加载多个配置文件到指定版本
func (cm *ConfigManager) LoadConfigsWithVersion(version string, jsonFiles []string) error {for _, jsonFile := range jsonFiles {err := cm.LoadConfigWithVersion(version, jsonFile)if err != nil {return fmt.Errorf("加载文件 %s 到版本 %s 失败: %v", jsonFile, version, err)}}return nil
}// GetConfigWithVersion 获取指定版本和文件的配置数据,并转换为目标类型
func (cm *ConfigManager) GetConfigWithVersion(version, jsonFile string, target interface{}) error {cm.mu.RLock()versionConfigs, versionExists := cm.versions[version]if !versionExists {cm.mu.RUnlock()return fmt.Errorf("版本 %s 不存在", version)}configStruct, exists := versionConfigs[jsonFile]cm.mu.RUnlock()if !exists {return fmt.Errorf("配置文件 %s 在版本 %s 中未加载,请先调用LoadConfigWithVersion", jsonFile, version)}// 将interface{}转换为JSON字节,再解析为目标类型// 这样可以处理任意类型的转换jsonData, err := json.Marshal(configStruct)if err != nil {return fmt.Errorf("序列化配置数据失败: %v", err)}err = json.Unmarshal(jsonData, target)if err != nil {return fmt.Errorf("反序列化到目标类型失败: %v", err)}return nil
}// GetRawConfigWithVersion 获取指定版本的原始配置数据
func (cm *ConfigManager) GetRawConfigWithVersion(version, jsonFile string) (interface{}, error) {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, versionExists := cm.versions[version]if !versionExists {return nil, fmt.Errorf("版本 %s 不存在", version)}configStruct, exists := versionConfigs[jsonFile]if !exists {return nil, fmt.Errorf("配置文件 %s 在版本 %s 中未加载", jsonFile, version)}return configStruct, nil
}// IsLoadedWithVersion 检查指定版本和文件是否已加载
func (cm *ConfigManager) IsLoadedWithVersion(version, jsonFile string) bool {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, versionExists := cm.versions[version]if !versionExists {return false}_, exists := versionConfigs[jsonFile]return exists
}// GetLoadedFilesWithVersion 获取指定版本的已加载文件列表
func (cm *ConfigManager) GetLoadedFilesWithVersion(version string) []string {cm.mu.RLock()defer cm.mu.RUnlock()versionConfigs, exists := cm.versions[version]if !exists {return []string{}}files := make([]string, 0, len(versionConfigs))for fileName := range versionConfigs {files = append(files, fileName)}return files
}// GetAllVersions 获取所有已加载的版本列表
func (cm *ConfigManager) GetAllVersions() []string {cm.mu.RLock()defer cm.mu.RUnlock()versions := make([]string, 0, len(cm.versions))for version := range cm.versions {versions = append(versions, version)}return versions
}// ReloadConfigWithVersion 强制重新加载指定版本的配置文件
func (cm *ConfigManager) ReloadConfigWithVersion(version, jsonFile string) error {cm.mu.Lock()defer cm.mu.Unlock()// 初始化版本映射(如果不存在)if cm.versions[version] == nil {cm.versions[version] = make(map[string]interface{})}// 删除现有配置delete(cm.versions[version], jsonFile)// 重新加载filePath := filepath.Join(config.AppConfig.App.ConfigDir, version, jsonFile)data, err := os.ReadFile(filePath)if err != nil {return fmt.Errorf("读取JSON文件 %s 失败: %v", filePath, err)}var configStruct interface{}err = json.Unmarshal(data, &configStruct)if err != nil {return fmt.Errorf("解析JSON失败: %v", err)}cm.versions[version][jsonFile] = configStructreturn nil
}// ReloadAllConfigsWithVersion 重新加载指定版本的所有已加载配置文件
func (cm *ConfigManager) ReloadAllConfigsWithVersion(version string) error {files := cm.GetLoadedFilesWithVersion(version)for _, file := range files {if err := cm.ReloadConfigWithVersion(version, file); err != nil {return fmt.Errorf("重新加载文件 %s 在版本 %s 失败: %v", file, version, err)}}return nil
}// ReloadAllVersions 重新加载所有版本的所有配置文件
func (cm *ConfigManager) ReloadAllVersions() error {versions := cm.GetAllVersions()for _, version := range versions {if err := cm.ReloadAllConfigsWithVersion(version); err != nil {return err}}return nil
}// UnloadConfigWithVersion 从指定版本中卸载配置文件
func (cm *ConfigManager) UnloadConfigWithVersion(version, jsonFile string) {cm.mu.Lock()defer cm.mu.Unlock()if cm.versions[version] != nil {delete(cm.versions[version], jsonFile)}
}// UnloadVersion 卸载整个版本
func (cm *ConfigManager) UnloadVersion(version string) {cm.mu.Lock()defer cm.mu.Unlock()delete(cm.versions, version)
}// Clear 清空所有已加载的配置
func (cm *ConfigManager) Clear() {cm.mu.Lock()defer cm.mu.Unlock()cm.versions = make(map[string]map[string]interface{})
}

调用

// 初始化配置管理器并加载监控data目录下的JSON文件cm := util.GetConfigManager()// 停止文件监控defer cm.StopWatch()// 获取data目录下的所有版本子目录versionDirs, err := filepath.Glob(filepath.Join(config.AppConfig.App.ConfigDir, "*"))if err != nil {return}// 遍历所有版本目录for _, versionDir := range versionDirs {// 获取版本号(目录名)version := filepath.Base(versionDir)// 获取当前版本目录下的所有JSON文件jsonFiles, err := filepath.Glob(filepath.Join(versionDir, "*.json"))if err != nil {continue}// 提取文件名(不包含路径)fileNames := make([]string, 0, len(jsonFiles))for _, file := range jsonFiles {fileNames = append(fileNames, filepath.Base(file))}// 加载当前版本的配置文件if err := cm.LoadConfigsWithVersion(version, fileNames); err != nil {continue}// 监控当前版本的配置文件if err := cm.WatchConfigFiles(version, fileNames); err != nil {continue}}

相关新闻

  • 2025年11月小程序商城服务商推荐前十排行榜单
  • 性价比高的全屋定制公司推荐,深圳这些企业口碑好值得考虑
  • 2025年东北三省金刚盲道服务公司推荐:三大金刚盲道选择哪家好?权威测评与深度解析

最新新闻

  • LLM与RNN混合架构在代码理解中的应用与优化
  • 河北福亚斯保温建材口碑怎么样?深度评测与推荐 - mypinpai
  • 2026年好用的PTFE管道品牌,推荐哪家? - mypinpai
  • 邢台黄金回收门店实地探访全记录 - 余生黄金回收
  • 岳阳黄金回收实测六家正规门店靠谱吗 - 余生黄金回收
  • 零基础看懂 FPGA 实现 IIR 滤波器:大白话 + 手算实例 + 代码全拆解

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号