Qt 5.9 XML文件写入指南


在Qt 5.9中,有多种方法可以编写XML文件。下面我将介绍三种主要方法,并提供完整的代码示例和最佳实践。

三种XML写入方法对比

方法优点缺点适用场景
QXmlStreamWriter高效、内存占用低无树形结构大型XML文件
QDomDocument树形结构、易操作内存占用高小型XML文件、需要频繁修改
Qt XML PatternsXQuery支持复杂、学习曲线陡需要XQuery/XPath

方法1:使用QXmlStreamWriter(推荐)

这是最高效的方法,特别适合大型XML文件:

#include <QXmlStreamWriter>
#include <QFile>
#include <QDebug>
#include <QDateTime>bool writeXmlWithStreamWriter(const QString &filename)
{// 使用QSaveFile确保原子写入(防掉电丢失)QSaveFile file(filename);if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {qWarning() << "无法打开文件:" << file.errorString();return false;}QXmlStreamWriter xml(&file);xml.setAutoFormatting(true);  // 自动格式化xml.setAutoFormattingIndent(2); // 缩进2个空格// 开始文档xml.writeStartDocument();// 根元素xml.writeStartElement("Data");xml.writeAttribute("version", "1.0");xml.writeAttribute("created", QDateTime::currentDateTime().toString(Qt::ISODate));// 写入注释xml.writeComment("这是一个使用QXmlStreamWriter生成的XML文件");// 书籍信息xml.writeStartElement("Books");for (int i = 1; i <= 3; ++i) {xml.writeStartElement("Book");xml.writeAttribute("id", QString::number(i));xml.writeTextElement("Title", QString("Qt编程指南 %1").arg(i));xml.writeTextElement("Author", QString("作者 %1").arg(i));xml.writeTextElement("Year", QString::number(2015 + i));xml.writeTextElement("Price", QString::number(35.5 + i));// 添加CDATA部分xml.writeStartElement("Description");xml.writeCDATA(QString("<p>这是第%1本书的描述,包含<strong>特殊字符</strong></p>").arg(i));xml.writeEndElement(); // Descriptionxml.writeEndElement(); // Book}xml.writeEndElement(); // Books// 用户信息xml.writeStartElement("Users");xml.writeEmptyElement("User"); // 空元素xml.writeAttribute("id", "1001");xml.writeAttribute("name", "张三");xml.writeAttribute("role", "管理员");xml.writeEndElement(); // Users// 结束文档xml.writeEndElement(); // Dataxml.writeEndDocument();// 提交文件(原子操作)if (!file.commit()) {qCritical() << "文件提交失败:" << file.errorString();return false;}qDebug() << "XML文件已成功写入:" << filename;return true;
}

方法2:使用QDomDocument(DOM方式)

适合小型XML文件或需要频繁修改的场景:

#include <QDomDocument>
#include <QFile>
#include <QDebug>bool writeXmlWithDomDocument(const QString &filename)
{// 创建DOM文档QDomDocument doc("XML_DOC");// 创建处理指令QDomProcessingInstruction pi = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");doc.appendChild(pi);// 创建根元素QDomElement root = doc.createElement("Data");root.setAttribute("version", "1.0");doc.appendChild(root);// 创建注释QDomComment comment = doc.createComment("这是一个使用QDomDocument生成的XML文件");root.appendChild(comment);// 创建书籍元素QDomElement booksElement = doc.createElement("Books");root.appendChild(booksElement);for (int i = 1; i <= 3; ++i) {QDomElement bookElement = doc.createElement("Book");bookElement.setAttribute("id", i);booksElement.appendChild(bookElement);QDomElement title = doc.createElement("Title");title.appendChild(doc.createTextNode(QString("Qt高级编程 %1").arg(i)));bookElement.appendChild(title);QDomElement author = doc.createElement("Author");author.appendChild(doc.createTextNode(QString("专家 %1").arg(i)));bookElement.appendChild(author);QDomElement year = doc.createElement("Year");year.appendChild(doc.createTextNode(QString::number(2018 + i)));bookElement.appendChild(year);}// 创建用户元素QDomElement usersElement = doc.createElement("Users");root.appendChild(usersElement);QDomElement userElement = doc.createElement("User");userElement.setAttribute("id", "1002");userElement.setAttribute("name", "李四");userElement.setAttribute("role", "编辑");usersElement.appendChild(userElement);// 写入文件QSaveFile file(filename);if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {qWarning() << "无法打开文件:" << file.errorString();return false;}// 使用缩进格式输出QTextStream out(&file);out.setCodec("UTF-8");doc.save(out, 2); // 缩进2个空格if (!file.commit()) {qCritical() << "文件提交失败:" << file.errorString();return false;}qDebug() << "XML文件已成功写入:" << filename;return true;
}

方法3:使用Qt XML Patterns(XQuery)

适合需要复杂XML转换的场景:

#include <QXmlQuery>
#include <QXmlFormatter>
#include <QBuffer>
#include <QFile>
#include <QDebug>bool writeXmlWithXmlPatterns(const QString &filename)
{// 创建XML查询QXmlQuery query(QXmlQuery::XQuery10);// 定义XQuery生成XMLQString xquery = R"(declare variable $books external;<Data version="1.0"><Books>{for $book in $books/Bookreturn $book}</Books><Users><User id="1003" name="王五" role="读者"/></Users></Data>)";// 绑定变量QBuffer booksData;booksData.open(QIODevice::ReadWrite);booksData.write(R"(<Books><Book id="4"><Title>Qt多线程编程</Title><Author>赵六</Author><Year>2022</Year></Book><Book id="5"><Title>QML高级技巧</Title><Author>钱七</Author><Year>2023</Year></Book></Books>)");booksData.seek(0);query.bindVariable("books", &booksData);query.setQuery(xquery);if (!query.isValid()) {qWarning() << "无效的XQuery";return false;}// 执行查询并格式化输出QBuffer outputBuffer;outputBuffer.open(QIODevice::ReadWrite);QXmlFormatter formatter(query, &outputBuffer);formatter.setIndentationDepth(2);if (!query.evaluateTo(&formatter)) {qWarning() << "XQuery执行失败";return false;}outputBuffer.seek(0);// 写入文件QSaveFile file(filename);if (!file.open(QIODevice::WriteOnly)) {qWarning() << "无法打开文件:" << file.errorString();return false;}file.write(outputBuffer.data());if (!file.commit()) {qCritical() << "文件提交失败:" << file.errorString();return false;}qDebug() << "XML文件已成功写入:" << filename;return true;
}

使用示例

#include <QCoreApplication>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QString filename = "example.xml";// 方法1:使用QXmlStreamWriterif (writeXmlWithStreamWriter("stream_writer.xml")) {qDebug() << "方法1成功";}// 方法2:使用QDomDocumentif (writeXmlWithDomDocument("dom_document.xml")) {qDebug() << "方法2成功";}// 方法3:使用Qt XML Patternsif (writeXmlWithXmlPatterns("xml_patterns.xml")) {qDebug() << "方法3成功";}return a.exec();
}

最佳实践

  1. 文件安全写入

    • 使用QSaveFile而不是QFile,确保写入操作的原子性
    • 避免写入过程中断电导致文件损坏
  2. 编码处理

    // 确保使用UTF-8编码
    xml.writeStartDocument("1.0", true); // 第二个参数表示使用UTF-8
    
  3. 错误处理

    if (xml.hasError()) {qWarning() << "XML写入错误:" << xml.errorString();
    }
    
  4. 验证XML结构

    // 在开发阶段验证XML
    #include <QXmlSchemaValidator>bool validateXml(const QString &filename, const QString &schemaFile) {QXmlSchema schema;if (!schema.load(schemaFile)) return false;QXmlSchemaValidator validator(schema);return validator.validate(filename);
    }
    
  5. 性能优化

    • 对于大型文件,使用QXmlStreamWriter
    • 避免在循环中频繁打开/关闭文件
    • 使用缓存机制批量写入数据

生成的XML示例

<?xml version="1.0" encoding="UTF-8"?>
<Data version="1.0" created="2023-08-15T14:30:45Z"><!--这是一个使用QXmlStreamWriter生成的XML文件--><Books><Book id="1"><Title>Qt编程指南 1</Title><Author>作者 1</Author><Year>2016</Year><Price>36.5</Price><Description><![CDATA[<p>这是第1本书的描述,包含<strong>特殊字符</strong></p>]]></Description></Book><Book id="2"><Title>Qt编程指南 2</Title><Author>作者 2</Author><Year>2017</Year><Price>37.5</Price><Description><![CDATA[<p>这是第2本书的描述,包含<strong>特殊字符</strong></p>]]></Description></Book><Book id="3"><Title>Qt编程指南 3</Title><Author>作者 3</Author><Year>2018</Year><Price>38.5</Price><Description><![CDATA[<p>这是第3本书的描述,包含<strong>特殊字符</strong></p>]]></Description></Book></Books><Users><User id="1001" name="张三" role="管理员"/></Users>
</Data>

常见问题解决

  1. 中文乱码问题

    // 确保使用UTF-8编码
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
    
  2. 文件权限问题

    // 设置正确的文件权限
    file.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
    
  3. 特殊字符处理

    • 使用writeCDATA()处理包含特殊字符的内容
    • 或者使用QString::toHtmlEscaped()进行转义
  4. 大文件内存消耗

    • 使用QXmlStreamWriter代替QDomDocument
    • 分块写入XML文件

在Qt 5.9中,推荐使用QXmlStreamWriter配合QSaveFile进行XML文件写入,这种方法高效、安全且内存占用低,适合大多数应用场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87195.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87195.shtml
英文地址,请注明出处:http://en.pswp.cn/web/87195.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一些ubuntu命令记录(持续补充)

一、查看代码运行占用的内存 1、使用 top 命令 top 命令是一个实时的系统监控工具&#xff0c;可以显示当前系统中所有进程的资源使用情况。运行以下命令&#xff1a; top 在 top 界面中&#xff0c;可以看到每个进程的内存使用情况&#xff08;%MEM 列&#xff09;。 如何…

今日学习:音视频领域入门文章参考(待完善)

音视频领域概览 入门文章参考 CSDN 雷神 博客园 2022-5-22

.npmrc和.yarnrc配置文件介绍:分别用于 Node.js 中的 npm(Node Package Manager)和 Yarn 包管理工具

.npmrc 和 .yarnrc 是两个配置文件&#xff0c;分别用于 Node.js 中的 npm&#xff08;Node Package Manager&#xff09;和 Yarn 包管理工具。它们存储了与包管理相关的配置选项&#xff0c;允许用户自定义和控制包的安装、版本、缓存等行为。下面是它们的详细说明&#xff1a…

数字人分身 + 矩阵系统聚合:源码搭建,支持OEM

在 AIGC 技术爆发的当下&#xff0c;数字人分身已从概念走向实用&#xff0c;而矩阵系统的聚合能力则让单个数字人分身突破场景限制&#xff0c;实现 “一人多岗” 的规模化应用。无论是企业客服、直播带货&#xff0c;还是教育培训、虚拟社交&#xff0c;数字人分身 矩阵系统…

学习昇腾开发的第12天--安装第三方依赖

第三方依赖安装指导&#xff08;C样例&#xff09; 前置条件 1. 按照官方指导文档完成CANN包安装。 2. CANN版本需要>5.0.4.alpha001&#xff0c;低于此版本请参见昇腾CANN样例仓介绍中的版本说明切换tag并使用发行版。 安装须知 samples仓中的部分c样例使用到opencv&am…

机器人仿真(1)Ubuntu24.04下CLion的ROS2开发环境配置

目录 一、前言二、配置要求安装ROS2安装CLion 三、配置步骤四、后记 一、前言 近日CLion已开放非商用免费使用。相比教程中常用的VSCode&#xff0c;CLion在自动补全、调试和环境变量配置等方面表现更为出色。不过截至本文撰写时&#xff0c;CLion官网仅提供了Windows系统下的…

WPF两种绑定方式的分析

一、两种绑定方式的分析 你提供的代码展示了两种不同的属性绑定实现方式&#xff1a;传统的CLR属性配合INotifyPropertyChanged接口&#xff0c;以及WPF依赖属性(DependencyProperty)系统。 相同点 目的相同&#xff1a;两种方式都是为了实现属性值变化时通知UI更新数据绑定…

【零基础学AI】第14讲:支持向量机实战 - 文本分类系统

本节课你将学到 理解支持向量机的核心思想和几何直觉 掌握SVM的关键参数和核函数选择 学会文本数据预处理和特征提取 完成一个邮件分类项目 对比SVM与其他算法的性能差异 开始之前 环境要求 Python 3.8内存: 建议2GB 需要安装的包 pip install pandas numpy scikit-learn …

美团 mtgsig1.2 最新版分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 部分代码 result cp.call…

【实战】CRMEB Pro 企业版安装教程(附 Nginx 反向代理配置 + 常见问题解决)

一、前言 CRMEB Pro 是一款企业级高并发高性能的电商系统&#xff0c;支持 Linux 服务器环境&#xff0c;需要 PHP 8.0 及以上版本&#xff0c;兼容多种 WEB 服务器&#xff08;如 Nginx 和 Apache&#xff09;&#xff0c;并支持 MySQL 数据库。本文将详细介绍如何从零开始安…

解决Linux下根目录磁盘空间不足的问题

ubantu中提示根目录磁盘空间不足 解决办法&#xff1a;对根目录磁盘空间进行扩展。 一、使用lsblk查看磁盘使用情况 命令行输入&#xff1a;lsblk aaaubuntu:~/Desktop$ lsblk可以看到sda5是挂载在根目录上的。所以我们要对sda5进行扩展 二、扩展硬盘空间 1、关闭虚拟机 2、…

【C++】--入门

前面我们学习C语言的时候&#xff0c;我们也有讲过C的部分历史&#xff0c;我们看其名字就知道其和我们的C语言肯定是有密不可分的关系的&#xff0c;我们的C是在C的基础上发展的&#xff0c;其弥补了C语⾔在表达能⼒、可维护性 和可扩展性⽅⾯的不⾜。 下面为C的近年来的几次…

JAVA内存区域划分

根据《JAVA虚拟机规范》的规定&#xff0c;JAVA虚拟机在执行JAVA程序的过程中会把内存划分为不同的数据区域。不同类型的数据会存储在不同的区域&#xff0c;理解JAVA内存区域的工作细节对理解JAVA多线程、线程安全性有着重要意义。 注意&#xff0c;JAVA内存区域的划分与我们…

Navicat 导入 SQL 文件

1. 安装并打开 Navicat 安装 Navicat&#xff08;如 Navicat Premium、Navicat for MySQL&#xff09;&#xff0c;百度或者淘宝就有很多破解版。 打开 Navicat&#xff0c;进入主界面。 2. 新建数据库连接 点击左上角 “连接” 按钮&#xff0c;选择你对应的数据库类型&…

《Go语言高级编程》玩转RPC

《Go语言高级编程》玩转RPC 一、客户端 RPC 实现原理&#xff1a;异步调用机制 Go 的 RPC 客户端支持同步和异步调用&#xff0c;核心在于 Client.Go 方法的实现&#xff1a; 1. 同步调用&#xff08;Client.Call&#xff09;的本质 func (client *Client) Call(serviceMet…

四大核心要素驱动汽车智能化创新与相关芯片竞争格局

作者&#xff1a;北京华兴万邦管理咨询有限公司 翔煜 商瑞 智能汽车时代的加速到来&#xff0c;使车载智能系统面临前所未有的算力需求。随着越来越多车型引入电子电气架构转向中心化、智能驾驶的多传感器融合、智能座舱的多模态交互以及生成式AI驱动的虚拟助手等创新技术&a…

照明新基建:塔能科技如何用数字骨骼支撑智慧城市生长

一、能源管理困局&#xff1a;双碳目标下的市政用电痛点 在双碳背景下&#xff0c;城市照明用电量已引起市政部门的重点关注。据国家统计局统计&#xff1a;我国城市照明用电量已占据全市城市用电量的28%&#xff0c;部分城市的照明用电量已高达35%以上&#xff0c;高压钠灯传统…

让Claude Code像Cursor一样好用

最近折腾AI工具&#xff0c;发现Claude Code真是个宝藏。但说实话&#xff0c;初学者一上手&#xff0c;十有八九会被命令行那一堆黑框框劝退。你以为你用熟了&#xff1f;其实你只解锁了Claude Code不到20%的威力&#xff0c;剩下的80%都藏在命令行背后的“黑魔法”里。00后谁…

ROS 2 中更改从设备(如电机控制器)的运动模式

在 ROS 2 中更改从设备&#xff08;如电机控制器&#xff09;的运动模式&#xff08;例如从位置模式切换到速度模式&#xff09;&#xff0c;需要通过操作模式&#xff08;Mode of Operation&#xff0c;对应对象字典索引0x6060&#xff09; 进行设置。结合你的配置&#xff08…

朴素贝叶斯分类

一、朴素贝叶斯算法概述 朴素贝叶斯(Naive Bayes)是一种基于贝叶斯定理的简单概率分类算法&#xff0c;它假设特征之间相互独立&#xff08;"朴素"的含义&#xff09;。尽管这个假设在现实中很少成立&#xff0c;但该算法在许多实际应用中表现优异&#xff0c;特别是…