Qt 5.9 XML文件寫入指南

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;特別是…