首页 / 财经 / 理财 / 正文

dialogresult(C# 上位机开发 三大数据格式)

放大字体  缩小字体 来源:vorwerk吸尘器 2026-04-17 17:05  浏览次数:11

C# 上位机开发 三大数据格式(Excel/XML/Json)导入导出完整方案

你需要的是 C# 上位机场景下 Excel、XML、Json 三种主流格式的全量数据持久化方案,以下内容兼顾无第三方依赖(XML/Json)和实战高效(Excel),适配 WinForm/WPF 上位机,可直接复用。

一、Json 数据导入导出(已优化,无第三方依赖)

基于.NET 自带System.Text.Json,无需 NuGet,适配.NET Core 3.0+/NET 5+,完美支持工控配置、采集数据场景。

1. 核心工具类

using System.IO;using System.Text;using System.Text.Json;/// <summary>/// Json 持久化工具类(System.Text.Json 版,无第三方依赖)/// </summary>public static class JsonPersistenceHelper{    // 全局序列化配置(解决工控场景中文、循环引用、null值问题)    private static readonly JsonSerializerOptions _jsonOptions = new()    {        WriteIndented = true, // 格式化缩进,方便人工编辑        DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,        ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles, // 忽略循环引用        PropertyNameCaseInsensitive = true, // 反序列化时大小写不敏感        Encoder = System.Text.Encodings.Web.JavascriptEncoder.UnsafeRelaxedJsonEscaping // 支持中文    };    /// <summary>    /// Json 导出(序列化)    /// </summary>    public static bool ExportJson<T>(T data, string savePath)    {        try        {            string jsonStr = JsonSerializer.Serialize(data, _jsonOptions);            // 不带BOM的UTF8编码,解决中文乱码            File.WriteAllText(savePath, jsonStr, new UTF8Encoding(false));            return true;        }        catch (Exception ex)        {            Console.WriteLine($"Json导出失败:{ex.Message}");            return false;        }    }    /// <summary>    /// Json 导入(反序列化)    /// </summary>    public static T? importJson<T>(string filePath)    {        try        {            if (!File.Exists(filePath)) return default;            string jsonStr = File.ReadAllText(filePath, new UTF8Encoding(false));            return JsonSerializer.Deserialize<T>(jsonStr, _jsonOptions);        }        catch (Exception ex)        {            Console.WriteLine($"Json导入失败:{ex.Message}");            return default;        }    }}

2. 调用示例(PLC 配置 / 采集数据通用)

// 沿用之前的PlcConfig/CollectData实体类,直接调用private void BtnJsonExport_Click(object sender, EventArgs e){    var config = new PlcConfig    {        IpAddress = "192.168.1.10",        Port = 102,        Rack = 0,        Slot = 1    };    using (SaveFileDialog sfd = new SaveFileDialog())    {        sfd.Filter = "Json文件|*.json|所有文件|*.*";        if (sfd.ShowDialog() == DialogResult.OK)        {            bool success = JsonPersistenceHelper.ExportJson(config, sfd.FileName);            MessageBox.Show(success ? "Json导出成功" : "Json导出失败");        }    }}private void BtnJsonimport_Click(object sender, EventArgs e){    using (OpenFileDialog ofd = new OpenFileDialog())    {        ofd.Filter = "Json文件|*.json|所有文件|*.*";        if (ofd.ShowDialog() == DialogResult.OK)        {            PlcConfig? config = JsonPersistenceHelper.importJson<PlcConfig>(ofd.FileName);            if (config != null)            {                // 赋值给界面控件                txtIp.Text = config.IpAddress;                MessageBox.Show("Json导入成功");            }        }    }}

二、XML 数据导入导出(无第三方依赖,.NET 自带)

XML 格式适用于结构化配置、标准化数据交互(如工控系统间协议传输),基于System.Xml.Serialization实现,无需额外引用。

1. 核心工具类

using System.IO;using System.Text;using System.Xml.Serialization;/// <summary>/// XML 持久化工具类(.NET自带,无第三方依赖)/// </summary>public static class XmlPersistenceHelper{    /// <summary>    /// XML 导出(序列化)    /// </summary>    public static bool ExportXml<T>(T data, string savePath)    {        try        {            // XmlSerializer 需指定泛型类型            XmlSerializer serializer = new XmlSerializer(typeof(T));            // 使用UTF8编码,解决中文乱码            using (StreamWriter sw = new StreamWriter(savePath, false, new UTF8Encoding(false)))            {                // 格式化XML,方便查看                serializer.Serialize(sw, data);            }            return true;        }        catch (Exception ex)        {            Console.WriteLine($"XML导出失败:{ex.Message}");            return false;        }    }    /// <summary>    /// XML 导入(反序列化)    /// </summary>    public static T? importXml<T>(string filePath)    {        try        {            if (!File.Exists(filePath)) return default;            XmlSerializer serializer = new XmlSerializer(typeof(T));            using (StreamReader sr = new StreamReader(filePath, new UTF8Encoding(false)))            {                object? result = serializer.Deserialize(sr);                return result is T ? (T)result : default;            }        }        catch (Exception ex)        {            Console.WriteLine($"XML导入失败:{ex.Message}");            return default;        }    }}

2. 调用示例(配置 / 批量数据通用)

// 导出XML(PLC配置)private void BtnXmlExport_Click(object sender, EventArgs e){    var config = new PlcConfig    {        IpAddress = "192.168.1.10",        Port = 102,        MonitorTags = new List<string> { "DB1.DBW0", "DB1.DBW2" }    };    using (SaveFileDialog sfd = new SaveFileDialog())    {        sfd.Filter = "XML文件|*.xml|所有文件|*.*";        sfd.Title = "导出PLC配置(XML)";        if (sfd.ShowDialog() == DialogResult.OK)        {            bool success = XmlPersistenceHelper.ExportXml(config, sfd.FileName);            MessageBox.Show(success ? "XML导出成功" : "XML导出失败");        }    }}// 导入XML(PLC配置)private void BtnXmlimport_Click(object sender, EventArgs e){    using (OpenFileDialog ofd = new OpenFileDialog())    {        ofd.Filter = "XML文件|*.xml|所有文件|*.*";        ofd.Title = "导入PLC配置(XML)";        if (ofd.ShowDialog() == DialogResult.OK)        {            PlcConfig? config = XmlPersistenceHelper.importXml<PlcConfig>(ofd.FileName);            if (config != null)            {                txtIp.Text = config.IpAddress;                txtPort.Text = config.Port.ToString();                MessageBox.Show("XML导入成功");            }            else            {                MessageBox.Show("XML导入失败或文件无效");            }        }    }}// 批量导出采集数据(XML)private void BtnXmlExportCollect_Click(object sender, EventArgs e){    List<CollectData> dataList = new List<CollectData>()    {        new CollectData{CollectTime=DateTime.Now, StationNo="ST01", Value=12.3m, IsQualified=true},        new CollectData{CollectTime=DateTime.Now, StationNo="ST02", Value=11.8m, IsQualified=true}    };    using (SaveFileDialog sfd = new SaveFileDialog())    {        sfd.Filter = "XML文件|*.xml|所有文件|*.*";        if (sfd.ShowDialog() == DialogResult.OK)        {            bool success = XmlPersistenceHelper.ExportXml(dataList, sfd.FileName);            MessageBox.Show(success ? "采集数据XML批量导出成功" : "导出失败");        }    }}

三、Excel 数据导入导出(实战高效,NPOI 版)

Excel 是上位机报表导出、批量数据交互的主流格式,优先使用NPOI(免费开源,支持.xls/.xlsx,无需安装 Office)。

1. 前置准备:安装 NPOI

通过 NuGet 安装:搜索NPOI,安装最新稳定版(支持.NET framework/.NET Core)。

2. 核心工具类(支持.xlsx,兼容批量数据)

using NPOI.SS.UserModel;using NPOI.XSSF.UserModel;using System.IO;using System.Text;/// <summary>/// Excel 持久化工具类(NPOI 版,支持.xlsx)/// </summary>public static class ExcelPersistenceHelper{    /// <summary>    /// Excel 导出(批量数据适配)    /// </summary>    /// <typeparam name="T">数据实体类型</typeparam>    /// <param name="dataList">数据列表</param>    /// <param name="savePath">保存路径</param>    /// <param name="headerDict">表头字典(键:实体属性名,值:表头显示名)</param>    public static bool ExportExcel<T>(List<T> dataList, string savePath, Dictionary<string, string> headerDict)    {        try        {            // 创建Excel工作簿(.xlsx格式)            IWorkbook workbook = new XSSFWorkbook();            ISheet sheet = workbook.CreateSheet("上位机数据"); // 工作表名称            // 1. 创建表头行            IRow headerRow = sheet.CreateRow(0);            int colIndex = 0;            // 存储属性名列表,用于后续赋值            List<string> propertyNames = new List<string>();            foreach (var kv in headerDict)            {                headerRow.CreateCell(colIndex).SetCellValue(kv.Value);                propertyNames.Add(kv.Key);                // 自动调整列宽                sheet.AutoSizeColumn(colIndex);                colIndex++;            }            // 2. 填充数据行            int rowIndex = 1;            foreach (var data in dataList)            {                IRow dataRow = sheet.CreateRow(rowIndex);                colIndex = 0;                // 反射获取实体属性值                var properties = typeof(T).GetProperties();                foreach (var propName in propertyNames)                {                    var prop = properties.FirstOrDefault(p => p.Name == propName);                    if (prop != null)                    {                        object? value = prop.GetValue(data);                        // 根据类型设置单元格值                        if (value != null)                        {                            if (value is DateTime datevalue)                            {                                dataRow.CreateCell(colIndex).SetCellValue(datevalue.ToString("yyyy-MM-dd HH:mm:ss"));                            }                            else if (value is int || value is decimal || value is double)                            {                                dataRow.CreateCell(colIndex).SetCellValue(Convert.ToDouble(value));                            }                            else if (value is bool boolValue)                            {                                dataRow.CreateCell(colIndex).SetCellValue(boolValue ? "是" : "否");                            }                            else                            {                                dataRow.CreateCell(colIndex).SetCellValue(value.ToString());                            }                        }                        else                        {                            dataRow.CreateCell(colIndex).SetCellValue("");                        }                    }                    sheet.AutoSizeColumn(colIndex);                    colIndex++;                }                rowIndex++;            }            // 3. 写入文件            using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write))            {                workbook.Write(fs);            }            workbook.Close();            return true;        }        catch (Exception ex)        {            Console.WriteLine($"Excel导出失败:{ex.Message}");            return false;        }    }    /// <summary>    /// Excel 导入(批量数据适配)    /// </summary>    /// <typeparam name="T">数据实体类型</typeparam>    /// <param name="filePath">文件路径</param>    /// <param name="headerDict">表头字典(键:实体属性名,值:表头显示名)</param>    public static List<T>? importExcel<T>(string filePath, Dictionary<string, string> headerDict) where T : new()    {        try        {            if (!File.Exists(filePath)) return null;            List<T> dataList = new List<T>();            // 读取Excel文件            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))            {                IWorkbook workbook = new XSSFWorkbook(fs);                ISheet sheet = workbook.GetSheetAt(0); // 获取第一个工作表                if (sheet == null) return null;                // 1. 验证表头(可选,提高容错性)                IRow headerRow = sheet.GetRow(0);                if (headerRow == null) return null;                // 表头显示名列表                List<string> headerNames = headerDict.Values.ToList();                for (int i = 0; i < headerNames.Count; i++)                {                    ICell cell = headerRow.GetCell(i);                    if (cell == null || cell.StringCellValue != headerNames[i])                    {                        Console.WriteLine("Excel表头不匹配,导入失败");                        return null;                    }                }                // 2. 读取数据行                var properties = typeof(T).GetProperties();                // 表头对应属性名                List<string> propNames = headerDict.Keys.ToList();                for (int rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)                {                    IRow dataRow = sheet.GetRow(rowIndex);                    if (dataRow == null) continue;                    T data = new T();                    for (int colIndex = 0; colIndex < propNames.Count; colIndex++)                    {                        string propName = propNames[colIndex];                        var prop = properties.FirstOrDefault(p => p.Name == propName);                        if (prop == null) continue;                        ICell cell = dataRow.GetCell(colIndex);                        if (cell == null) continue;                        // 根据属性类型赋值                        Type propType = prop.PropertyType;                        // 处理可空类型                        propType = Nullable.GetUnderlyingType(propType) ?? propType;                        object? cellValue = null;                        switch (cell.CellType)                        {                            case CellType.String:                                cellValue = cell.StringCellValue;                                break;                            case CellType.Numeric:                                if (DateUtil.IsCellDateFormatted(cell))                                {                                    cellValue = cell.DateCellValue;                                }                                else                                {                                    cellValue = cell.NumericCellValue;                                }                                break;                            case CellType.Boolean:                                cellValue = cell.BooleanCellValue;                                break;                            default:                                cellValue = null;                                break;                        }                        // 类型转换并赋值                        if (cellValue != null && !string.IsNullOrEmpty(cellValue.ToString()))                        {                            try                            {                                cellValue = Convert.ChangeType(cellValue, propType);                                prop.SetValue(data, cellValue);                            }                            catch                            {                                // 类型转换失败则跳过该字段                                continue;                            }                        }                    }                    dataList.Add(data);                }            }            return dataList;        }        catch (Exception ex)        {            Console.WriteLine($"Excel导入失败:{ex.Message}");            return null;        }    }}

3. 调用示例(采集数据批量导出 / 导入)

// 导出Excel(采集记录)private void BtnExcelExport_Click(object sender, EventArgs e){    // 模拟采集数据    List<CollectData> dataList = new List<CollectData>()    {        new CollectData{CollectTime=DateTime.Now, StationNo="ST01", Value=12.3m, IsQualified=true, Remark="正常"},        new CollectData{CollectTime=DateTime.Now, StationNo="ST02", Value=11.8m, IsQualified=true, Remark="正常"},        new CollectData{CollectTime=DateTime.Now, StationNo="ST03", Value=15.6m, IsQualified=false, Remark="超上限"}    };    // 定义表头(键:实体属性名,值:Excel表头显示名)    Dictionary<string, string> headerDict = new Dictionary<string, string>()    {        { "CollectTime", "采集时间" },        { "StationNo", "工位号" },        { "Value", "采集值" },        { "IsQualified", "是否合格" },        { "Remark", "备注" }    };    using (SaveFileDialog sfd = new SaveFileDialog())    {        sfd.Filter = "Excel文件(*.xlsx)|*.xlsx|所有文件|*.*";        sfd.Title = "批量导出采集记录(Excel)";        if (sfd.ShowDialog() == DialogResult.OK)        {            bool success = ExcelPersistenceHelper.ExportExcel(dataList, sfd.FileName, headerDict);            MessageBox.Show(success ? $"Excel导出成功,共{dataList.Count}条记录" : "Excel导出失败");        }    }}// 导入Excel(采集记录)private void BtnExcelimport_Click(object sender, EventArgs e){    // 表头字典(需与导出时一致)    Dictionary<string, string> headerDict = new Dictionary<string, string>()    {        { "CollectTime", "采集时间" },        { "StationNo", "工位号" },        { "Value", "采集值" },        { "IsQualified", "是否合格" },        { "Remark", "备注" }    };    using (OpenFileDialog ofd = new OpenFileDialog())    {        ofd.Filter = "Excel文件(*.xlsx)|*.xlsx|所有文件|*.*";        ofd.Title = "批量导入采集记录(Excel)";        if (ofd.ShowDialog() == DialogResult.OK)        {            List<CollectData>? dataList = ExcelPersistenceHelper.importExcel<CollectData>(ofd.FileName, headerDict);            if (dataList != null && dataList.Count > 0)            {                // 绑定到DataGridView显示                dgvCollect.DataSource = dataList;                MessageBox.Show($"Excel导入成功,共{dataList.Count}条记录");            }            else            {                MessageBox.Show("Excel导入失败或文件无有效数据");            }        }    }}

四、三种格式适用场景对比(上位机开发参考)

数据格式

核心优势

适用场景

依赖情况

Json

轻量、简洁、易解析、兼容性强

PLC 配置、机器人参数、轻量采集记录、跨系统接口

无(.NET 自带)

XML

结构化强、可扩展、支持命名空间、标准化

工控协议交互、复杂配置文件、需严格格式校验的场景

无(.NET 自带)

Excel

可视化强、支持公式 / 格式、用户易编辑

生产报表、批量数据导入导出、人工核对数据

NPOI(免费开源)

五、上位机开发避坑要点

  1. 编码统一:三种格式均使用UTF8编码(Excel 通过 NPOI 默认支持,Json/XML 显式指定),避免工控电脑中文乱码;
  2. 异常处理:导入导出时增加try-catch,并通过MessageBox/ 日志提示用户,提高上位机稳定性;
  3. 文件对话框:统一使用SaveFileDialog(导出)/OpenFileDialog(导入),符合上位机操作习惯;
  4. 大文件处理:Excel/Json 大文件(>100MB)建议分块导出,避免内存溢出;XML 不适合超大文件存储。

总结

  1. Json/XML 基于.NET 自带类库,无需第三方依赖,优先用于配置存储和标准化数据交互;
  2. Excel 使用 NPOI 实现,支持可视化报表,是批量数据人工交互的最优选择;
  3. 三个工具类均封装为静态类,调用简洁,可直接集成到 WinForm/WPF 上位机项目中;
  4. 配套调用示例覆盖工控常用场景(PLC 配置、采集记录),无需大幅修改即可复用。
打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心