C# 上位机 XML 数据导入导出(工控场景最佳实践)
适配 WinForm/WPF,极简可直接复用,兼顾工控数据结构化 + 容错性
✅核心方案(2 种常用)
方案 1:XmlSerializer(推荐,工控结构化数据首选)
优点:强类型、易维护,适配 PLC 参数 / 设备配置 / 生产记录等结构化数据
1. 先定义实体类(工控示例)
cs
// 必须加[Serializable],属性需带get/set
[Serializable]
public class DeviceConfig // 工控设备配置,可直接改字段适配你的场景
{
public string DeviceName { get; set; } // 设备名称
public int PLCAddress { get; set; } // PLC地址
public int BaudRate { get; set; } // 波特率
public List<ChannelParam> Channels { get; set; } // 通道参数(集合)
}
[Serializable]
public class ChannelParam
{
public string ChannelName { get; set; }
public float UpperLimit { get; set; } // 上限
public float LowerLimit { get; set; } // 下限
}
2. 导出 XML(一键保存)
cs
/// <summary>
/// XML导出(带异常处理,工控场景防丢数据)
/// </summary>
/// <param name="data">要保存的实体数据</param>
/// <param name="filePath">保存路径(如D:\设备配置.xml)</param>
public bool ExportToXml<T>(T data, string filePath)
{
try
{
// 创建目录,避免路径不存在报错
var dir = Path.GetDirectoryName(filePath);
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
var serializer = new XmlSerializer(typeof(T));
using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
serializer.Serialize(fs, data);
}
return true;
}
catch (Exception ex)
{
MessageBox.Show($"导出失败:{ex.Message}");//上位机弹窗提示
return false;
}
}
// 调用示例(上位机按钮点击事件)
private void btnExport_Click(object sender, EventArgs e)
{
// 构造测试数据(实际替换为你的业务数据)
var config = new DeviceConfig
{
DeviceName = "流水线机器人1号",
PLCAddress = 1,
BaudRate = 9600,
Channels = new List<ChannelParam>
{
new ChannelParam{ChannelName="温度",UpperLimit=80,LowerLimit=20},
new ChannelParam{ChannelName="压力",UpperLimit=1.0f,LowerLimit=0.2f}
}
};
// 选择保存路径
using (var sfd = new SaveFileDialog())
{
sfd.Filter = "XML文件|*.xml";
if (sfd.ShowDialog() == DialogResult.OK)
{
ExportToXml(config, sfd.FileName);
}
}
}
3. 导入 XML(一键读取)
cs
/// <summary>
/// XML导入(强类型解析,直接绑定业务数据)
/// </summary>
public T ImportFromXml<T>(string filePath) where T : class
{
try
{
if (!File.Exists(filePath)) return null;
var serializer = new XmlSerializer(typeof(T));
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
return serializer.Deserialize(fs) as T;
}
}
catch (Exception ex)
{
MessageBox.Show($"导入失败:{ex.Message}");
return null;
}
}
// 调用示例(按钮点击)
private void btnImport_Click(object sender, EventArgs e)
{
using (var ofd = new OpenFileDialog())
{
ofd.Filter = "XML文件|*.xml";
if (ofd.ShowDialog() == DialogResult.OK)
{
var config = ImportFromXml<DeviceConfig>(ofd.FileName);
if (config != null)
{
// 绑定到上位机界面控件(示例)
txtDeviceName.Text = config.DeviceName;
txtPLCAddr.Text = config.PLCAddress.ToString();
// 集合数据绑定到DataGridView
dgvChannels.DataSource = config.Channels;
}
}
}
}
方案 2:XDocument(灵活,适配非结构化 / 动态 XML)
适合字段不固定的场景(如临时日志、自定义参数)
导出 + 导入示例
cs
// 导出
public void ExportXmlByXDoc(string filePath)
{
var doc = new XDocument(
new XDeclaration("1.0", "UTF-8", "yes"),
new XElement("DeviceConfig",
new XElement("DeviceName", "流水线机器人1号"),
new XElement("PLCAddress", 1),
new XElement("Channels",
new XElement("Channel",
new XElement("Name", "温度"),
new XElement("Upper", 80)
)
)
)
);
doc.Save(filePath);
}
// 导入
public void ImportXmlByXDoc(string filePath)
{
if (!File.Exists(filePath)) return;
var doc = XDocument.Load(filePath);
// 读取节点
var devName = doc.Element("DeviceConfig").Element("DeviceName").Value;
var plcAddr = int.Parse(doc.Element("DeviceConfig").Element("PLCAddress").Value);
}
✅工控场景关键优化(必加)
-
编码统一:指定
UTF-8,避免中文乱码(XmlSerializer 默认 UTF-8,XDocument 需手动声明) -
路径选择:固定上位机默认路径(如
Application.StartupPath + "/Config/"),方便部署 -
异常处理:必须捕获 IO / 序列化异常,避免上位机闪退
-
版本兼容:实体类新增字段加
[XmlIgnore](可选字段),兼容旧 XML 文件cs[XmlIgnore] // 新增字段不序列化,不影响旧文件导入 public string NewField { get; set; }
✅引用 & 注意
-
必加命名空间(不用额外 NuGet,原生支持)
csusing System.Xml; using System.Xml.Serialization; using System.Xml.Linq; using System.IO; -
实体类注意:不能是抽象类,属性必须有
get/set,否则序列化失败 -
大文件适配:工控大批量数据(如生产日志),用
XmlReader/XmlWriter流式读写,不占内存