C# 如何将DataSet保存为xml数据?

来源:MAC教程作者:三上悠亚头衔:网络博主
导读:本期聚焦于三上悠亚创作的《C# 如何将DataSet保存为xml数据?》,敬请观看详情。要在C#里把DataSet持久化为XML文件,不少人会直接用GetXml拿到字符串再手动写文件,这样虽然简单,但容易丢失表结构、关系和编码信息。实际上DataSet提供了WriteXml方法,支持输出纯数据、内联架构和DiffGram三种模式,也能直接写入文件、流和XmlWriter。本文围绕WriteXml的基础调用、XmlWriteMode选项以及编码与命名空间控制展开,对比GetXml与WriteXml的适用边界,演示从物理文件、字符串到XmlWriter的几种保存路径,并给出避免中文乱码、文件占用和格式混乱的实践建议,帮助你把内存数据可靠地转成XML。

DataSet 是 ADO.NET 中用来在内存里保存多张表及其关系的容器,很多业务场景需要把查询结果导出为 XML 文件,比如做数据交换、生成配置文件或临时备份。在 C# 中实现这个需求最简单也最推荐的方式就是调用 DataSet 自带的 WriteXml 方法,而不是手动拼接 XML 字符串。WriteXml 会根据 DataTable 的结构和行数据生成标准 XML 文档,还能按需包含架构信息,避免接收方不知道字段类型和约束。

C# 如何将DataSet保存为xml数据?

接下来分别从文件保存、写入模式控制和字符流输出几个角度展开。每个角度都会给出可运行代码,并解释不同选项的适用场景。

一、使用 WriteXml 将 DataSet 保存到 XML 文件

WriteXml 最常用的重载是接受一个文件路径,直接把整个 DataSet 序列化到磁盘。假设我们有一个包含客户信息的 DataSet,里面有一张 Customers 表,包含 Id、Name 和 CreatedAt 三列。先创建表结构、添加几行数据,然后调用 WriteXml 保存。代码大致如下:

using System;
using System.Data;

class Program
{
    static void Main()
    {
        DataSet ds = new DataSet("CustomerDataSet");
        DataTable table = new DataTable("Customers");

        table.Columns.Add("Id", typeof(int));
        table.Columns.Add("Name", typeof(string));
        table.Columns.Add("CreatedAt", typeof(DateTime));

        table.Rows.Add(1, "张三", new DateTime(2024, 3, 1));
        table.Rows.Add(2, "李四", new DateTime(2024, 3, 5));

        ds.Tables.Add(table);

        ds.WriteXml(@"C:\temp\customers.xml");
        Console.WriteLine("已保存");
    }
}

这段代码会把 DataSet 写到 C:\temp\customers.xml 文件中。默认情况下 WriteXml 只导出数据,不包含表结构。也就是说生成的文件中会有 <CustomerDataSet> 根节点,下面挂着多个 <Customers> 行节点,但不会包含列的类型、是否允许空等信息。对于只需要交换数据的场景这已经够用,但如果接收方需要根据 XML 重建表结构,就得额外指定模式。

还要注意路径中的反斜杠,C# 普通字符串里 @ 前缀可以避免转义,因此 @"C:\temp\customers.xml" 会按原样保留每一个反斜杠。如果不用 @,需要写成 "C:\\temp\\customers.xml"。文件所在目录必须存在,否则会抛出 DirectoryNotFoundException。

文件写入过程是同步的,如果数据量很大,UI 线程可能会卡顿,此时可以把 WriteXml 放到后台任务中执行。另外 WriteXml 会覆盖已存在的同名文件,如果不想覆盖,可以先判断 File.Exists 再决定是否备份。

二、用 XmlWriteMode 控制 XML 内容和结构

WriteXml 除了路径参数,还可以传入第二个参数 XmlWriteMode。该枚举有三个值:IgnoreSchema、WriteSchema 和 DiffGram。IgnoreSchema 是默认行为,只写数据;WriteSchema 会在 XML 中内联写入 XSD 架构,包含表名、列名、类型和约束;DiffGram 则是一种特殊格式,同时保存原始数据和修改后的数据,适用于跟踪数据变更和合并冲突。

下面的代码演示三种模式生成文件的差异。为了方便比较,使用同一个 DataSet 分别保存到三个文件:

using System;
using System.Data;

class Program
{
    static void Main()
    {
        DataSet ds = CreateDataSet();

        ds.WriteXml(@"C:\temp\data_only.xml", XmlWriteMode.IgnoreSchema);
        ds.WriteXml(@"C:\temp\data_with_schema.xml", XmlWriteMode.WriteSchema);
        ds.WriteXml(@"C:\temp\data_diffgram.xml", XmlWriteMode.DiffGram);

        Console.WriteLine("三种模式已输出");
    }

    static DataSet CreateDataSet()
    {
        DataSet ds = new DataSet("OrderDataSet");
        DataTable orders = new DataTable("Orders");
        orders.Columns.Add("OrderId", typeof(int));
        orders.Columns.Add("Product", typeof(string));
        orders.Columns.Add("Quantity", typeof(int));

        orders.Rows.Add(101, "键盘", 2);
        orders.Rows.Add(102, "鼠标", 5);

        ds.Tables.Add(orders);
        return ds;
    }
}

如果打开 data_only.xml,内容大致是 <OrderDataSet> 根节点下只有行数据;而 data_with_schema.xml 会先出现 <xs:schema> 节点,里面定义 <Orders> 表的列类型和主键等信息,随后才是数据部分。DiffGram 文件则包含 <diffgr:diffgram> 命名空间,用来区分原值和当前值。

选择哪种模式取决于用途:给第三方系统交换数据时,IgnoreSchema 更精简;需要让对方知道字段类型或后续用 ReadXml 恢复结构时,WriteSchema 更稳妥;如果要把 DataSet 当作变更跟踪容器,例如在多层架构中传递增删改结果,DiffGram 是适合的。注意 WriteSchema 会显著增加文件体积,因为每张表的每个字段都会有架构描述,数据量小的时候无所谓,大数据量下要权衡。

三、将 DataSet 保存为字符串或流,并处理编码问题

有些场景不一定要写到物理文件,例如需要在内存中生成 XML 字符串返回给前端,或者通过 HTTP 响应流输出。DataSet 还提供了 WriteXml 的重载,接受 Stream、TextWriter 和 XmlWriter 对象。如果只是想快速拿到 XML 字符串,也可以调用 GetXml 方法,但 GetXml 只能输出 IgnoreSchema 的数据,无法包含架构信息,而且字符编码由框架内部决定。

推荐的做法是使用 StringWriter 配合 WriteXml,并指定 XmlWriteMode,这样既能拿到字符串又能带上架构。示例:

using System;
using System.Data;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        DataSet ds = new DataSet("ProductDataSet");
        DataTable products = new DataTable("Products");
        products.Columns.Add("Id", typeof(int));
        products.Columns.Add("Name", typeof(string));
        products.Columns.Add("Price", typeof(decimal));

        products.Rows.Add(1, "显示器", 999.9m);
        products.Rows.Add(2, "机械键盘", 399.0m);
        ds.Tables.Add(products);

        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            ds.WriteXml(sw, XmlWriteMode.WriteSchema);
        }

        string xml = sb.ToString();
        Console.WriteLine(xml);
    }
}

StringWriter 默认使用 UTF-16 编码,如果最终要写入文件或网络流,需要确认接收方支持的编码。若想生成 UTF-8 字节数组,可以使用 MemoryStream 和 StreamWriter,并指定 Encoding.UTF8。要注意 WriteXml 内部写 XML 声明时,编码信息来自 TextWriter 的 Encoding 属性。比如用 new StreamWriter(stream, Encoding.UTF8) 得到的 XML 声明会是 <?xml version="1.0" encoding="utf-8"?>。

另外如果保存到文件时遇到中文乱码,通常是因为文件编码和读取端不一致。WriteXml 重载中接受 Stream 时,可以自己创建 FileStream 和 StreamWriter,明确指定 UTF-8 或 GBK。例如 using (StreamWriter sw = new StreamWriter(@"C:\temp\data.xml", false, Encoding.UTF8)) { ds.WriteXml(sw); },这样能保证中文字符按 UTF-8 写入。不要依赖默认编码,不同环境下默认编码可能不同。

还有一个常见问题是 XML 中的特殊字符,比如小于号、大于号和与符号。WriteXml 会自动转义这些字符,因此如果数据列中包含类似英文的与符号,输出会自动变成合法的 XML 实体,从而保持 XML 合法。这也是不建议手动拼接 XML 的原因之一,因为手动拼接很容易漏掉转义。

四、用 XmlWriter 精细控制格式与命名空间

如果希望生成的 XML 有缩进、指定命名空间,或者在写入过程中进行流式处理,可以用 XmlWriter 配合 WriteXml。XmlWriter 可以通过 XmlWriterSettings 设置 Indent 为 true,让输出内容可读性更好。代码先创建 XmlWriterSettings,设置缩进和编码,然后创建 XmlWriter 指向文件,最后调用 ds.WriteXml(writer, XmlWriteMode.WriteSchema)。

using System;
using System.Data;
using System.Text;
using System.Xml;

class Program
{
    static void Main()
    {
        DataSet ds = new DataSet("UserDataSet");
        DataTable users = new DataTable("Users");
        users.Columns.Add("UserId", typeof(int));
        users.Columns.Add("UserName", typeof(string));
        users.Rows.Add(1, "王五");
        users.Rows.Add(2, "赵六");
        ds.Tables.Add(users);

        XmlWriterSettings settings = new XmlWriterSettings
        {
            Indent = true,
            IndentChars = "  ",
            Encoding = Encoding.UTF8,
            NewLineOnAttributes = false
        };

        using (XmlWriter writer = XmlWriter.Create(@"C:\temp\users_pretty.xml", settings))
        {
            ds.WriteXml(writer, XmlWriteMode.IgnoreSchema);
        }

        Console.WriteLine("带缩进的 XML 已保存");
    }
}

通过 XmlWriterSettings 生成的 XML 会包含换行和缩进,每个元素层级用两个空格表示,阅读起来更清晰。如果不需要架构信息,可以传 IgnoreSchema;如果需要对方校验字段类型,则改成 WriteSchema。使用 XmlWriter 还可以在写入前添加命名空间声明,但 DataSet 的 WriteXml 本身不提供直接设置默认命名空间的重载,需要包装一个自定义 XmlWriter 或在写入后处理命名空间。不过对于大多数数据导出场景,默认命名空间并不影响使用。

保存完成后,读取时可以使用 DataSet.ReadXml 方法恢复。ReadXml 支持自动识别内联架构,如果 XML 是 WriteSchema 生成的,读取后 DataSet 会自动包含表结构;如果是 IgnoreSchema 生成的,则列类型会被推断为 string。另外如果 XML 是 DiffGram 格式,ReadXml 也能自动还原原始数据和修改后数据,通常配合 DataSet.Merge 使用。

在真实项目中,往往不只是把 DataSet 写成 XML,还需要处理并发、日志和异常。建议把 WriteXml 封装成通用方法,比如 SaveDataSetToXml(DataSet ds, string filePath, XmlWriteMode mode),内部做目录检查、文件备份和 try-catch。这样既避免重复代码,也能统一编码策略。总之,优先使用 WriteXml 而不是 GetXml 或手动拼接,可以最大程度减少编码乱码、特殊字符转义和架构丢失问题。

C# DataSetDataSet保存XMLWriteXml修改时间:2026-09-20 10:58:34

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0920/59619.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。