从零搭建工业控制系统(十四):配置系统基础,INI + JSON
2026/9/14 20:49:17 网站建设 项目流程

配置系统基础:INI + JSON 怎么管

这是「从零搭建工业控制系统」系列第14篇。前面几篇一直在说"从配置读取",这篇终于讲配置系统本身——INI管全局参数,JSON管命令定义。下一篇讲热加载。


配置文件的三座大山

项目里的配置分三类,各管各的:

类型文件管什么格式
全局参数Config.iniIP地址、超时、开关INI
命令定义*.jsonc阀门/伺服/设备命令JSONC
工艺参数*.jsonPPS阈值、报警参数JSON

为什么不全用JSON?因为INI对操作员友好。车间的人用记事本打开Config.ini,改个IP改个超时,一目了然。JSON的嵌套结构对非技术人员不友好。


ConfigReader:单例读取器

ConfigReaderini-parser库封装了INI文件的读写。单例模式,线程安全:

public class ConfigReader { private static readonly object _lockObject = new object(); private static ConfigReader _instance; private readonly FileIniDataParser _parser; private readonly string _configFilePath; public static ConfigReader Instance { get { if (_instance == null) { lock (_lockObject) { if (_instance == null) { _instance = new ConfigReader(Paths.WorkingConfigIni); } } } return _instance; } } private ConfigReader(string configFilePath) { _configFilePath = configFilePath; _parser = new FileIniDataParser(); _parser.Parser.Configuration.CommentString = ";"; } }

注释符改成;而不是默认的#,因为Windows用户习惯分号注释。


AppConfig:配置数据模型

AppConfig是一个纯数据类,所有属性都有默认值。配置文件缺失某项时不报错,用默认值:

[Obfuscation(Exclude = true, ApplyToMembers = true)] public class AppConfig { public bool AutoStart { get; set; } public bool ShowUILog { get; set; } = true; public bool ShowCallerInfoInUILog { get; set; } = false; // 设备通信参数 public string DigitalIOIp { get; set; } public int DigitalIOPort { get; set; } public int DigitalIOReadTimeout { get; set; } = 5000; public string ValveModuleIp { get; set; } public int ValveModulePort { get; set; } public int ValveModuleReadTimeout { get; set; } = 5000; public string AnalogIOIp { get; set; } public int AnalogIOPort { get; set; } public int AnalogIOReadTimeout { get; set; } = 5000; // 灯塔配置 public bool TowerLightServiceEnable { get; set; } = true; public int BuzzerDurationSeconds { get; set; } = 5; // Chamber控制 public bool AutoAllowControl { get; set; } = true; public bool ManualAllowControl { get; set; } = true; }

Obfuscation(Exclude=true)保护属性名不被混淆——因为这些属性在XAML里通过{x:Static}引用。


读取配置的坑

读取INI配置有个容易忽略的坑:新增配置项后,旧配置文件没有这个key

// 读取ChamberControl节 if (data.Sections.ContainsSection("ChamberControl")) { var chamberControl = data["ChamberControl"]; config.AutoAllowControl = GetBoolValue(chamberControl, "AutoAllowControl", true); config.ManualAllowControl = GetBoolValue(chamberControl, "ManualAllowControl", true); }

GetBoolValue第三个参数是默认值。旧配置文件没有AutoAllowControl这个key时,返回默认值true

踩过的坑:之前DevicePanelViewModel里初始值设为false,但AppConfig默认true。程序启动后配置文件还没读取就用了ViewModel的初始值,导致UI显示未勾选但实际逻辑按true执行。后来统一了默认值才解决。


JSONC配置:命令定义

命令配置用JSONC格式(带注释的JSON)。CommandRegistry加载这些文件:

Configs/ ├── ValveActions.jsonc # 阀门动作 ├── MotionCommands.jsonc # 运动命令 ├── HardwareCommands.jsonc # 硬件命令 ├── TrackingCommands.jsonc # 追踪命令 ├── RecipeCommands.jsonc # 配方流程命令 └── OnlyDebug/ # 调试覆盖配置 └── *.jsonc

OnlyDebug目录下的同名文件会覆盖主配置,方便调试时临时修改命令参数而不影响生产配置。


IO配置的disabled字段

JSON配置支持disabled字段控制IO是否加载:

{ "address": "0xXX", "name": "DI_XX", "disabled": true }

不配置disabled就是启用,只有需要禁用才加这个字段。读取时过滤掉:

public List<DeviceIO> GetInputDevicesByJsonOrder() { return _inputDevices .Where(d => !d.Disabled) .ToList(); }

比删掉配置项更安全——配置还在,只是不加载。哪天需要启用改回false就行。


配置保存的完整流程

操作员在设置界面修改参数后点保存:

// 1. ViewModel收集UI值 config.AutoAllowControl = AutoAllowControl; config.ManualAllowControl = ManualAllowControl; config.TowerLightServiceEnable = TowerLightServiceEnable; // 2. 调用ConfigReader写入文件 ConfigReader.Instance.WriteConfig(config); // 3. 触发配置变更通知 WeakReferenceMessenger.Default.Send(new ConfigChangedMessage()); // 4. 安全服务收到消息后响应

写文件和发消息是两步。写完文件不发消息,其他服务不知道配置变了。发消息但不写文件,重启后配置丢失。两步缺一不可。


配置踩坑清单

现象解决
默认值不一致UI和逻辑用的默认值不同统一在AppConfig里定义
旧文件缺key读取报错GetBoolValue带默认值参数
多次Changed热加载触发多次500ms防抖Timer
混淆后属性名变了XAML绑定失效Obfuscation排除
配置改了不生效服务不知道配置变了消息机制通知

本篇小结

知识点关键做法
INI vs JSONINI给操作员,JSON给开发
默认值AppConfig属性全带默认值
调试覆盖OnlyDebug目录覆盖主配置
IO禁用disabled字段过滤,不删配置
配置变更写文件 + 发消息,缺一不可

配置系统的核心:操作员改了能生效,程序重启不丢失,默认值保证安全。


下期预告

第15篇:配置热重载机制

配置基础说完了,下篇讲热加载——FileSystemWatcher监听文件变化、防抖处理、注册表热更新,改配置不用重启程序。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询