当前位置: 首页 > 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都是配置文件的最佳选择。

http://www.xdnf.cn/news/1034281.html

相关文章:

  • synchronized和ReentrantLock的区别
  • gpt3大模型蒸馏后效果会变差么
  • HTTP 请求报文 方法
  • 湖北理元理律师事务所债务优化实务:平衡还款与生活的法律路径
  • 2022mpsPTE岗位笔试题
  • 自动化立体仓库堆垛机控制系统STEP7 FC1功能块 读取位置值SSI接口
  • KJY0047-J1阶段测试
  • 模拟 AJAX 提交 form 表单及请求头设置详解
  • 人工智能学习24-BP激活函数
  • 全球化2.0|云轴科技ZStack联合Teleplex举办技术沙龙 · 吉隆坡站
  • Oracle 单实例双IP配置
  • Qt:Qt桌面程序正常退出注意事项
  • 人工智能学习16-Numpy
  • YOLOv2 训练过程详解:从数据到模型落地的全流程解析
  • 设计模式-创建型模式(详解)
  • 11_13小结
  • 每天一个前端小知识 Day 1
  • 迁移数据库服务器和应用服务器步骤
  • Vue3中v-bind=“$attrs“应用实例
  • 最小费用最大流算法
  • 架构下的最终瓶颈:数据库如何破局?
  • ARDM:一款国产跨平台的Redis管理工具
  • React项目常用目录结构
  • 细节致胜:如何重塑反向海淘用户体验
  • MongoDB 事务有哪些限制和注意事项?
  • 系统学习·PHP语言
  • sqli-labs靶场46-53关(综合)
  • c 语言如何将 uint8_t *tg_pFrames的数据给 uint8_t **ppJpg
  • YOLO11中的C3K2模块
  • AORSA关键文件及参数解释