当前位置: 首页 > news >正文

读取配置文件到Settings对象的完整实现

在这里插入图片描述

文章目录

    • 1. 定义配置模型类
    • 2. 创建示例config.json文件
    • 3. 实现配置读取器
    • 4. 使用示例
    • 5. 扩展ModbusTcpHelper类
    • 6. 配置验证增强版
    • 7. 处理特殊需求
  • 配置文件种类及其比较:JSON配置文件的优势
    • 一、常见配置文件类型及示例
      • 1. JSON (JavaScript Object Notation)
      • 2. XML (eXtensible Markup Language)
      • 3. YAML (YAML Ain't Markup Language)
      • 4. INI (Initialization File)
      • 5. 环境变量
      • 6. 二进制格式
    • 二、JSON配置文件的优势
      • 1. 可读性强
      • 2. 数据结构丰富
      • 3. 跨平台兼容性好
      • 4. 工具生态完善
      • 5. 性能优异
      • 6. 现代开发标准
      • 7. 支持注释(通过变通方式)
    • 三、各类型配置文件对比表
    • 四、JSON配置的典型应用场景
      • 1. 应用程序配置
      • 2. IoT设备配置
      • 3. 网络服务配置
    • 五、JSON配置的最佳实践
    • 六、何时不选择JSON
    • 七、总结

在这里插入图片描述

下面我将展示如何从config.json文件读取配置并转换为强类型的Settings对象,使用.NET 8和System.Text.Json。

1. 定义配置模型类

首先创建表示配置结构的模型类:

public class ModbusSettings
{public string IpAddress { get; set; }public int Port { get; set; }public byte SlaveId { get; set; }public int TimeoutMs { get; set; } = 5000;public List<RegisterMap> RegisterMaps { get; set; }
}public class RegisterMap
{public string Name { get; set; }public ushort Address { get; set; }public DataType DataType { get; set; }public float ScalingFactor { get; set; } = 1.0f;
}public enum DataType
{UInt16,Int16,UInt32,Int32,Float
}

2. 创建示例config.json文件

{"IpAddress": "192.168.1.202","Port": 4196,"SlaveId": 40,"TimeoutMs": 3000,"RegisterMaps": [{"Name": "Temperature","Address": 22,"DataType": "Float","ScalingFactor": 0.1},{"Name": "Pressure","Address": 26,"DataType": "Float"}]
}

3. 实现配置读取器

using System.Text.Json;
using System.Text.Json.Serialization;public static class ConfigLoader
{private static readonly JsonSerializerOptions _options = new(){PropertyNameCaseInsensitive = true,Converters = { new JsonStringEnumConverter() },AllowTrailingCommas = true,ReadCommentHandling = JsonCommentHandling.Skip};public static ModbusSettings LoadConfig(string filePath = "config.json"){try{if (!File.Exists(filePath)){throw new FileNotFoundException($"配置文件 {filePath} 不存在");}string json = File.ReadAllText(filePath);var settings = JsonSerializer.Deserialize<ModbusSettings>(json, _options);if (settings == null){throw new InvalidOperationException("配置文件内容为空或格式不正确");}// 验证必要配置if (string.IsNullOrWhiteSpace(settings.IpAddress)){throw new InvalidDataException("IP地址不能为空");}if (settings.Port <= 0 || settings.Port > 65535){throw new InvalidDataException("端口号必须在1-65535范围内");}return settings;}catch (JsonException ex){throw new InvalidOperationException($"配置文件解析失败: {ex.Message}", ex);}}// 可选:保存配置的方法public static void SaveConfig(ModbusSettings settings, string filePath = "config.json"){var options = new JsonSerializerOptions{WriteIndented = true,Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,Converters = { new JsonStringEnumConverter() }};string json = JsonSerializer.Serialize(settings, options);File.WriteAllText(filePath, json);}
}

4. 使用示例

class Program
{static async Task Main(){try{// 加载配置var settings = ConfigLoader.LoadConfig();Console.WriteLine($"成功加载配置: {settings.IpAddress}:{settings.Port}");// 使用配置初始化Modbus帮助类var modbusHelper = new ModbusTcpHelper(settings.IpAddress, settings.Port);await modbusHelper.ConnectAsync(settings.TimeoutMs);// 读取配置中定义的寄存器foreach (var map in settings.RegisterMaps){try{// 根据数据类型读取数据object value = map.DataType switch{DataType.Float => await ReadFloatRegister(modbusHelper, settings.SlaveId, map),_ => await ReadStandardRegister(modbusHelper, settings.SlaveId, map)};// 应用缩放因子if (value is float floatValue && map.ScalingFactor != 1.0f){value = floatValue * map.ScalingFactor;}Console.WriteLine($"{map.Name} ({map.Address}): {value}");}catch (Exception ex){Console.WriteLine($"读取 {map.Name} 失败: {ex.Message}");}}}catch (Exception ex){Console.WriteLine($"发生错误: {ex.Message}");}}private static async Task<object> ReadFloatRegister(ModbusTcpHelper helper, byte slaveId, RegisterMap map){// 浮点数需要读取2个寄存器(4字节)float[] values = await helper.ReadFloatRegistersAsync(slaveId, map.Address, 2);return values[0];}private static async Task<object> ReadStandardRegister(ModbusTcpHelper helper, byte slaveId, RegisterMap map){// 读取单个寄存器ushort[] values = await helper.ReadRegistersAsync(slaveId, map.Address, 1);return map.DataType switch{DataType.UInt16 => values[0],DataType.Int16 => (short)values[0],_ => throw new NotSupportedException($"不支持的数据类型: {map.DataType}")};}
}

5. 扩展ModbusTcpHelper类

在之前的ModbusTcpHelper类中添加以下方法以支持更多数据类型:

/// <summary>
/// 读取标准寄存器值
/// </summary>
public async Task<ushort[]> ReadRegistersAsync(byte slaveId, ushort startAddress, ushort registerCount)
{byte[] request = new byte[6];request[0] = slaveId;request[1] = 0x03; // 功能码: 读保持寄存器request[2] = (byte)(startAddress >> 8);request[3] = (byte)(startAddress & 0xFF);request[4] = (byte)(registerCount >> 8);request[5] = (byte)(registerCount & 0xFF);byte[] response = await SendRequestAsync(request);// 提取寄存器数据(每个寄存器2字节)ushort[] registers = new ushort[registerCount];for (int i = 0; i < registerCount; i++){int offset = 3 + i * 2;registers[i] = (ushort)((response[offset] << 8) | response[offset + 1]);}return registers;
}

6. 配置验证增强版

可以添加更详细的配置验证:

public class ModbusSettingsValidator
{public static void Validate(ModbusSettings settings){if (settings == null)throw new ArgumentNullException(nameof(settings));if (string.IsNullOrWhiteSpace(settings.IpAddress))throw new InvalidDataException("IP地址不能为空");if (!IPAddress.TryParse(settings.IpAddress, out _))throw new InvalidDataException("IP地址格式不正确");if (settings.Port < 1 || settings.Port > 65535)throw new InvalidDataException("端口号必须在1-65535范围内");if (settings.SlaveId < 1 || settings.SlaveId > 247)throw new InvalidDataException("从站ID必须在1-247范围内");if (settings.TimeoutMs < 100)throw new InvalidDataException("超时时间不能小于100ms");if (settings.RegisterMaps == null || settings.RegisterMaps.Count == 0)throw new InvalidDataException("至少需要配置一个寄存器映射");foreach (var map in settings.RegisterMaps){if (string.IsNullOrWhiteSpace(map.Name))throw new InvalidDataException("寄存器名称不能为空");if (map.Address > 65535)throw new InvalidDataException($"寄存器地址 {map.Name} 超出范围");if (map.ScalingFactor == 0)throw new InvalidDataException($"缩放因子 {map.Name} 不能为零");}}
}// 在ConfigLoader中使用
var settings = JsonSerializer.Deserialize<ModbusSettings>(json, _options);
ModbusSettingsValidator.Validate(settings);

7. 处理特殊需求

如果需要支持更复杂的配置,如:

  1. 自定义字节序:在RegisterMap中添加ByteOrder属性
  2. 位操作:支持读取线圈和离散输入
  3. 批量读取优化:配置中定义哪些寄存器可以批量读取

示例扩展配置:

{"BatchReads": [{"Name": "SensorGroup1","StartAddress": 22,"Count": 4,"MapsTo": ["Temperature", "Humidity", "Pressure", "Voltage"]}]
}

这种架构提供了灵活的配置方式,同时保持了类型安全和良好的错误处理。


配置文件种类及其比较:JSON配置文件的优势

一、常见配置文件类型及示例

1. JSON (JavaScript Object Notation)

示例

{"appSettings": {"name": "数据采集系统","version": "1.2.0","debugMode": false,"sampleRate": 1000},"modbus": {"ip": "192.168.1.202","port": 502,"timeout": 3000}
}

2. XML (eXtensible Markup Language)

示例

<configuration><appSettings><name>数据采集系统</name><version>1.2.0</version><debugMode>false</debugMode><sampleRate>1000</sampleRate></appSettings><modbus><ip>192.168.1.202</ip><port>502</port><timeout>3000</timeout></modbus>
</configuration>

3. YAML (YAML Ain’t Markup Language)

示例

appSettings:name: "数据采集系统"version: "1.2.0"debugMode: falsesampleRate: 1000modbus:ip: "192.168.1.202"port: 502timeout: 3000

4. INI (Initialization File)

示例

[appSettings]
name=数据采集系统
version=1.2.0
debugMode=false
sampleRate=1000[modbus]
ip=192.168.1.202
port=502
timeout=3000

5. 环境变量

示例

APP_NAME=数据采集系统
APP_VERSION=1.2.0
MODBUS_IP=192.168.1.202
MODBUS_PORT=502

6. 二进制格式

示例:通常不可读,如Windows注册表、Protocol Buffers等

二、JSON配置文件的优势

1. 可读性强

JSON采用键值对结构和缩进格式,比XML更简洁:

{"user": {"name": "张三","age": 30,"active": true}
}

对比XML:

<user><name>张三</name><age>30</age><active>true</active>
</user>

2. 数据结构丰富

支持多种数据类型:

  • 对象(嵌套结构)
  • 数组
  • 字符串
  • 数字
  • 布尔值
  • null
{"devices": [{"id": 1,"type": "sensor","registers": [40001, 40002, 40003]},{"id": 2,"type": "actuator","enabled": true}]
}

3. 跨平台兼容性好

  • 所有现代编程语言都内置JSON支持
  • Web应用天然支持
  • 移动端和嵌入式系统也能轻松处理

4. 工具生态完善

  • 验证工具:JSON Schema验证
  • 格式化工具:VS Code等编辑器内置支持
  • 转换工具:可轻松转换为其他格式
  • 在线工具:各种JSON在线解析和美化工具

5. 性能优异

  • 解析速度比XML快
  • 比YAML更高效
  • 体积通常比XML小30%-50%

6. 现代开发标准

  • REST API的标准数据格式
  • NoSQL数据库(如MongoDB)使用类似JSON的BSON
  • 前端框架(React/Vue等)直接支持

7. 支持注释(通过变通方式)

虽然标准JSON不支持注释,但可以通过以下方式实现:

{"//note": "这是设备配置","device": {"ip": "192.168.1.100","//status": "active|inactive","status": "active"}
}

三、各类型配置文件对比表

特性JSONXMLYAMLINI环境变量二进制
可读性★★★★★★★★☆☆★★★★★★★★☆☆★★☆☆☆☆☆☆☆☆
数据结构★★★★★★★★★★★★★★★★★☆☆☆★☆☆☆☆★★★★★
跨平台支持★★★★★★★★★★★★★★☆★★★☆☆★★★★★★★★☆☆
工具生态★★★★★★★★★★★★★★☆★★★☆☆★★★☆☆★★☆☆☆
解析性能★★★★★★★★☆☆★★★☆☆★★★★★★★★★★★★★★★
适合场景通用复杂结构人工维护简单配置容器化高性能

四、JSON配置的典型应用场景

1. 应用程序配置

{"logging": {"level": "debug","path": "/var/log/app.log"},"database": {"connectionString": "Server=db;Database=appdb","timeout": 30}
}

2. IoT设备配置

{"deviceId": "SN-12345","sensors": [{"type": "temperature","address": 40001,"unit": "°C"},{"type": "humidity","address": 40003,"scale": 0.1}]
}

3. 网络服务配置

{"endpoints": {"api": "https://api.example.com/v1","auth": "https://auth.example.com"},"retryPolicy": {"maxAttempts": 3,"delay": 1000}
}

五、JSON配置的最佳实践

  1. 使用有意义的键名

    // 不好
    "t": 30// 好
    "temperature": 30
    
  2. 合理组织层次结构

    {"modbus": {"tcp": {"ip": "192.168.1.100","port": 502},"rtu": {"port": "COM3","baudRate": 9600}}
    }
    
  3. 添加配置版本控制

    {"configVersion": "1.1","settings": {// ...}
    }
    
  4. 为重要配置添加默认值

    {"timeout": 5000,  // 默认5秒"retries": 3      // 默认3次
    }
    
  5. 使用JSON Schema验证

    {"$schema": "./config-schema.json",// 实际配置内容
    }
    

六、何时不选择JSON

虽然JSON有很多优点,但在以下情况可能需要考虑其他方案:

  1. 需要注释:考虑YAML
  2. 极简配置:考虑INI或环境变量
  3. 高性能场景:考虑二进制格式
  4. 人工编辑频繁:考虑YAML(更友好的格式)

七、总结

JSON作为配置文件格式具有以下核心优势:

  1. 完美的平衡性:在可读性、功能性和性能之间取得最佳平衡
  2. 语言无关性:几乎所有现代编程语言都原生支持
  3. 层次化结构:能清晰表达复杂配置关系
  4. 扩展性强:支持数组、嵌套对象等复杂数据结构
  5. 工具链完善:从编辑器支持到验证工具一应俱全

对于大多数应用场景,特别是需要表达结构化数据、跨平台使用或与现代Web技术栈集成的场景,JSON都是配置文件的最佳选择。

相关文章:

  • 【AS32系列MCU调试教程】驱动开发:AS32驱动库的集成与应用实例
  • 拓展:###单向循环链表###
  • comfyui插件和comfyui mac安装
  • 设备被看门狗重置问题
  • RHCE 练习四:编写脚本实现以下功能
  • web方向第一次考核内容
  • Linux免驱使用slcan,使用方法以Ubuntu为例
  • g++ a.cpp -o a ‘pkg-config --cflags --libs opencv4‘/usr/bin/ld: 找不到 没有那个文件或目录
  • [特殊字符] Next.js Turbo 模式不支持 @svgr/webpack 的原因与解决方案
  • Redis的list的底层原理
  • 后端通过nignx代理转发,提供接口供前端在防火墙外访问
  • Arduino入门教程​​​​​​​:4、打印字符到电脑
  • python中的模块化编程:日期模块、math算术模块、random模块
  • 国学IP行业实战洞察:聚焦创客匠人,解锁创始人IP与知识变现新路径
  • TDengine 如何从 2.x 迁移到 3.0
  • 用bilibili一个讲座视频,生成一本科普书籍
  • 苍穹外卖-day09
  • 湖北理元理律师事务所债务优化实务:平衡还款与生活的法律路径
  • (下)通用智能体与机器人Transformer:Gato和RT-1技术解析及与LLM Transformer的异同
  • uni-app项目实战笔记10--设置页面全局渐变线性渐变背景色
  • wordpress修改注册页面/网站关键词排名优化工具
  • 网站做聚合页面方案如何写/seo自然排名
  • 内蒙古集宁建设厅官方网站/刷排名seo软件
  • 一般网站有哪几部分构成/日照seo公司
  • 兴安盟做网站公司/阿里巴巴推广
  • wordpress添加地图吗/广州营销优化