最近在学习 Qt 读写XML文件时,思考了一个问题,除了DOM和SAX外,还有没有更快捷的读写XML的方法?经过一番面向搜索引擎编程,我还真发现了一种方法——流读写XML(Write and read by stream)。今天就借此文向大家分享一下这种方法。
三种读写XML方式的对比
DOM方式 |
SAX方式 |
流读写方式 |
XML被存入内存 |
速度快,逐行扫描 |
速度快,一次性传入 |
消耗内存较多 |
操作复杂,很难修改 |
不支持修改和删除 |
频繁操作较为方便 |
可以随时停止解析,对大型文档友好 |
读写API分离 |
看完对比,你是不是跃跃欲试了?下面我贴上我的练习代码,给你作为参考。
*.pro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| QT += core gui xml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \ main.cpp \ widget.cpp
HEADERS += \ widget.h
FORMS += \ widget.ui
qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
|
widget.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #ifndef WIDGET_H #define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE
class Widget : public QWidget { Q_OBJECT
public: Widget(QWidget *parent = nullptr); ~Widget();
int write_xml();
int read_xml();
private: Ui::Widget *ui; }; #endif
|
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include "widget.h" #include <QApplication> #include <QFile> #include <QXmlStreamWriter> #include <QXmlReader> #include <QtDebug> #include <QStringList>
int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget(); return a.exec(); }
|
widget.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#include "widget.h" #include "ui_widget.h" #include <QFile> #include <QXmlStreamWriter> #include <QtDebug> #include <QStringList>
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); int resWrite = write_xml(); if (resWrite < 0) { qDebug() << "ERRO : Write failed!"; } else { qDebug() << "INFO : Write succeed!"; }
int resRead = read_xml(); if(resRead < 0) { qDebug() << "ERRO : Read failed!"; } else { qDebug() << "INFO : Read succeed!"; } }
Widget::~Widget() { delete ui; }
int Widget::write_xml() { QStringList urls_list; QStringList name_list; QStringList stockList; urls_list << "https://cn.bing.com" << "https://google.com" << "https://baidu.com" << "https://sougou.com" << "https://mi.com"; name_list << "Bing" << "Google" << "Baidu" << "Sougou" << "Xiaomi"; stockList << "MSFT.US" << "GOOG.US" << "BIDU.US" << "SOGO.US" << "01810.HK";
QFile file("test.xml"); if (!file.open(QFile::WriteOnly | QFile::Text)) { qDebug() << QString("ERRO : Connot open file test.xml(%2)") .arg(file.errorString()); return -1; } QXmlStreamWriter stream(&file); stream.setCodec("UTF-8"); stream.setAutoFormatting(true); stream.writeStartDocument("1.0", true); stream.writeStartElement("compangy"); for(int i = 0; i < urls_list.size(); i++) { stream.writeStartElement("tech"); stream.writeAttribute("name", name_list.at(i)); stream.writeAttribute("url", urls_list.at(i)); stream.writeTextElement("stock_code", stockList.at(i)); stream.writeEndElement(); qDebug() << QString("[ %1-%2 ] write succeed!") .arg(name_list.at(i)) .arg(urls_list.at(i)); } stream.writeEndElement(); stream.writeEndDocument(); file.close(); return 1; }
int Widget::read_xml() { QString strFile("test.xml"); QFile file(strFile); if(!file.open(QFile::ReadOnly | QFile::Text)) { qDebug() << QString("ERRO : Connot open file %1(%2)") .arg(strFile) .arg(file.errorString()); return -1; }
QXmlStreamReader reader(&file);
reader.readNext();
while(!reader.atEnd()) { QXmlStreamReader::TokenType nType = reader.readNext();
if(nType == QXmlStreamReader::StartDocument) { qDebug() << "DocEncoding = " << reader.documentEncoding() << "DocVersion = " << reader.documentVersion(); }
if(reader.isStartElement()) { if(reader.name() == "tech") { qDebug() << "<" << reader.name() << ">"; if (reader.attributes().hasAttribute("name")) qDebug() << reader.attributes() .value("name"); if (reader.attributes().hasAttribute("url")) qDebug() << reader.attributes() .value("url"); reader.readNext(); } else if(reader.name() == "stock_code") { qDebug() << "<" << reader.name() << ">"; qDebug() << reader.readElementText(); reader.readNext(); } else { reader.readNext(); }
if (nType == QXmlStreamReader::EndElement) qDebug() << "</" << reader.name() << ">";
if(nType == QXmlStreamReader::Characters && !reader.isWhitespace()) qDebug() << reader.text(); } } if(reader.hasError()) { qDebug() << "ERRO : " << reader.errorString(); return -1; }
file.close(); return 1; }
|
test.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <compangy> <tech name="Bing" url="https://cn.bing.com"> <stock_code>MSFT.US</stock_code> </tech> <tech name="Google" url="https://google.com"> <stock_code>GOOG.US</stock_code> </tech> <tech name="Baidu" url="https://baidu.com"> <stock_code>BIDU.US</stock_code> </tech> <tech name="Sougou" url="https://sougou.com"> <stock_code>SOGO.US</stock_code> </tech> <tech name="Xiaomi" url="https://mi.com"> <stock_code>01810.HK</stock_code> </tech> </compangy>
|
在学习这种读写方式时,我也踩了一些坑。
- XML有且只有一个根节点。
- 良好的方法封装有利于降低代码(模块)间的耦合;
- 错误信息输出、注释在新学习时必不可少;
好了,本期的分享就到此为止了。如果对你有启发,欢迎转载~