C++ Xml解析的效率比较(Qt/TinyXml2/RapidXml/PugiXml)

article/2025/9/13 8:33:10

C++ Xml解析的效率比较(Qt/TinyXml2/RapidXml/PugiXml)


  • C Xml解析的效率比较QtTinyXml2RapidXmlPugiXml
    • 问题背景
    • 测试环境
    • Qt - QDomDocument
    • TinyXml-2
    • RapidXml
    • PugiXml
    • 总结


通常我们在一些软件的初始化或者保存配置时都会遇到对XML文件的操作,包括读写xml文件,解析内容等等。在我的工作中就遇到了这么一个问题,就是在ARM平台下Qt解析xml文件非常的慢,最初怀疑是我的操作有问题或者是ARM平台下的文件操作本身就很慢,于是就开始调查到底是哪里的效率问题,下面是一些测试分享给大家。

问题背景

下面一段代码是前面提到的运行效率低的一段代码:

QString filename = "...";
QFile file( filename );//< step1 open file
if( !file.open(QIODevice::ReadOnly) )
{qDebug() << "failed in opening file!";return false;
}//< step2 read file content
QDomDocument doc;       //< #include <qdom.h>
if( !doc.setContent( &file ) )
{qDebug() << "failed in setting content!";file.close();return false;
}
file.close();
...  //< operations on the content of file!

起初以为是文件打开和关闭耗时太多,所以在文件open和close函数前后都获取了系统时间来测试了函数消耗时间,结果是耗时很短,反而是 doc.setContent 耗费了非常长的时间,这才发现原来是Qt获取XML文件内容且Dom模型结构花费了太多时间,所以我们开始寻求效率更高的解决方案。

测试环境

Windows:
system:windows 10
cpu: intel core-i5-5200u @2.2GHz
IDE: visual studio 2010
compiler: VC10

Linux:
system: Debian 4.4.5-8
cpu: intel core-i5-3450 @3.3GHz
IDE: VIM
compiler: gcc version 4.4.5

  • Qt版本: 4.8.4
  • 用来测试的文件名为 DriverConfig.xml,大小为245Kb,共1561行,大部分内容为中文
  • 比较项有 TinyXml2, QDomDocument,因为从接口来看这两者的操作方式很类似,后面我会加入其它的xml解析库的比较,如 xmlbooster 等。

Qt - QDomDocument

下面是利用Qt中的xml支持来读取文件内容的源代码:


#include <QtCore/QCoreApplication>
#include <qdom.h>
#include <QFile>
#include <QIODevice>
#include <iostream>
#ifdef Q_OS_WIN
# include <Windows.h>
#else
# include <sys/time.h>
#endifusing std::cout;
using std::endl;#define TEST_TIMES 10int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);#ifdef Q_OS_WIN  //< windowslong tStart = 0;long tEnd   = 0;LARGE_INTEGER nFreq;LARGE_INTEGER nStartTime;LARGE_INTEGER nEndTime;double time = 0.;QueryPerformanceFrequency(&nFreq);QFile file( "D:/DriverConfig.xml" );QDomDocument doc;for( int i = 0; i < TEST_TIMES; ++i ){doc.clear();//< step1 open fileif( !file.open(QIODevice::ReadOnly) ){cout << "failed to open file!" << endl;continue;}Sleep( 100 );QueryPerformanceCounter(&nStartTime); //< step2 set contentif( !doc.setContent(&file) ){cout << "Failed to read xml file!" << endl;}QueryPerformanceCounter(&nEndTime);time = (double)(nEndTime.QuadPart-nStartTime.QuadPart) / (double)nFreq.QuadPart * 1000.;  //< mscout << " seting content costs " << time << "ms" << endl;file.close();Sleep( 100 );}#else //< LINUXtimeval starttime, endtime;QFile file( "/home/liuyc/DriverConfig.xml" );QDomDocument doc;double timeuse = 0.;double timeAverage = 0.;for( int i = 0; i < TEST_TIMES; ++i ){doc.clear();//< step1 open fileif( !file.open(QIODevice::ReadOnly) ){cout << "failed to open file!" << endl;continue;}sleep( 1 );  //< delay for 1sgettimeofday( &starttime, 0 );//< step2 set contentif( !doc.setContent(&file) ){cout << "Failed to read xml file!" << endl;continue;}gettimeofday( &endtime, 0 );timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse *= 0.001 ;timeAverage += timeuse;cout << " reading files costs : " << timeuse << "ms" << endl;file.close();sleep( 1 );  //< delay for 1s}timeAverage /= TEST_TIMES;cout << " The End *****************\n    average costs = " << timeAverage << "ms" << endl; #endifreturn a.exec();
}

下面来看看windows下的运行结果:
这里写图片描述
当时我的反应是 WTF?? 为什么同一个函数读同一个文件十次会有这么大的差异所以我才会在文件打开和关闭时分别都加了延时,希望避免文件开关的过程对这个函数产生的影响,结果依然没有解决这个问题,这个问题希望有大神帮我解答一下!

那下面我们来看linux下的运行结果:
这里写图片描述
显然,linux下这个时间相对的稳定可信,所以我们后面的测试也只要以linux下的时间作为参考。

TinyXml-2

下面我们来看利用tinyxml2实现读取的源代码:

#include <iostream>
#include "tinyxml2.h"
#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif
using namespace tinyxml2;
using std::cout;
using std::endl;#define TEST_TIMES  10int main()
{
#ifndef _WIN32  //< linux ------------------------------------------------tinyxml2::XMLDocument doc;timeval starttime, endtime;double timeuse = 0.;double timeAverage = 0.;for( int i = 0; i < TEST_TIMES; ++i ){gettimeofday( &starttime, 0 );if( XML_SUCCESS != doc.LoadFile( "/home/liuyc/DriverConfig.xml" ) ){cout << "failed in load xml file! _ " << i << endl;continue;}gettimeofday( &endtime, 0 );timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse *= 0.001 ;cout << " reading files costs : " << timeuse << "ms" << endl;timeAverage += timeuse;}timeAverage /= TEST_TIMES;cout << " \n** The end *******************\n    the average costs = " << timeAverage << "ms" << endl;#else  //< windows ---------------------------------------------------LARGE_INTEGER nFreq;LARGE_INTEGER nStartTime;LARGE_INTEGER nEndTime;double time = 0.;QueryPerformanceFrequency(&nFreq);tinyxml2::XMLDocument doc;for( int i = 0; i < TEST_TIMES; ++i ){QueryPerformanceCounter(&nStartTime); if( XML_SUCCESS != doc.LoadFile( "D:/DriverConfig.xml" ) ){cout << "failed in load xml file! _ " << i << endl;continue;}QueryPerformanceCounter(&nEndTime);time = (double)(nEndTime.QuadPart-nStartTime.QuadPart) / (double)nFreq.QuadPart * 1000.;  //< mscout << " reading files costs : " << time << "ms" << endl;}cout << endl;system("pause");#endif  //< end of windows ---------------------------------------------------return 0;
}

接下来先看linux下的运行结果(windows下的运行结果已经没有太多参考价值了):
linux_tinyxml_result
linux下的表现依然很稳定,这里我们可以得出一个很明显的结论,tinyxml的处理效率要比QDomDocument的处理效率高很多(这里的数据大致是4倍,但不包括对于xml文件内部信息的处理的其他函数接口的调用)。

虽然没什么参考价值,但还是看一下windows下的测试结果:
windows_tiny_result
这里效率也明显的比Windows Qt提升很多,而且执行时间也相对稳定了一,所以前一个测试中运行时间十分不稳定的情况暂定为Qt本身实现的问题,具体是什么问题或者在高版本的Qt里面是否已解决尚无答案。

RapidXml

注:RapidXml版本: 1.13
在RapidXml Manual的介绍中可以看到它和TinyXml以及其他的一些xml解析库做了对比(这里面tinyXml是最慢的),原文中介绍这是目前Xml解析最快的

As a rule of thumb, parsing speed is about 50-100x faster than Xerces DOM, 30-60x faster than TinyXml, 3-12x faster than pugxml, and about 5% - 30% faster than pugixml, the fastest XML parser I know of.

所以这里我也想要试试看RapidXml在内容解析时的效率表现,下面是源代码:

#include <iostream>
#include "rapidxml.hpp"
#include "rapidxml_print.hpp"
#include "rapidxml_utils.hpp"
#ifdef _WIN32
# include <Windows.h>
#else
# include <sys/time.h>
#endifusing namespace rapidxml;
using std::cout;
using std::endl;#define TEST_TIMES  10int main()
{
#ifdef _WIN32  //< windowsLARGE_INTEGER nFreq;LARGE_INTEGER nStartTime;LARGE_INTEGER nEndTime;double time = 0.;QueryPerformanceFrequency(&nFreq);//< parse xmlfor( int i = 0 ; i < TEST_TIMES; ++i ){rapidxml::file<> filename( "D:/DriverConfig.xml" );xml_document<> doc;QueryPerformanceCounter(&nStartTime); doc.parse<0>( filename.data() );QueryPerformanceCounter(&nEndTime);time = (double)(nEndTime.QuadPart-nStartTime.QuadPart) / (double)nFreq.QuadPart * 1000.;  //< mscout << " reading files costs : " << time << "ms" << endl;doc.clear();}system("pause");#elsetimeval starttime, endtime;double timeuse = 0.;double timeAverage = 0.;//< parse xmlfor( int i = 0 ; i < TEST_TIMES; ++i ){rapidxml::file<> filename( "/home/liuyc/DriverConfig.xml" );xml_document<> doc;gettimeofday( &starttime, 0 );doc.parse<0>( filename.data() );gettimeofday( &endtime, 0 );timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse *= 0.001 ;cout << " reading files costs : " << timeuse << "ms" << endl;doc.clear();timeAverage += timeuse;}timeAverage /= TEST_TIMES;cout << " \n** The end *******************\n    the average costs = " << timeAverage << "ms" << endl;#endifreturn 0;
}

同样,先看linux下运行的结果:
linux_rapidxml_result
效率确实为 TinyXml2 的2.x倍,但是并没有像 rapidXml 的说明手册里说的有30~60倍的效率差异(手册中是和TinyXml比较的,而不是TinyXml2),这里我不清楚到底是TinyXml2相对TinyXml有了明显的效率提升还是我在RapidXml的使用上有问题,后面需要再仔细调查RapidXml的接口使用方法。
在我自己初步的使用来看,我觉得 RapidXml 的接口并有 Qt 和 TinyXml2 那么简单易用,所以在文件大小不大或对效率要求不是很极限的情况下,使用 TinyXml2 可能会获得开发效率和运行效率的双赢。

再来看一下windows下的运行结果:
windows_rapid_reslut
依然不是很稳定,所以只做参考。

PugiXml

更新与2017.05.03

经博友提醒,现添加pugixml的测试,为节省篇幅只贴出 linux 下的测试代码(代码与 tinyxml 非常相似),可以看到pugixml与tinyxml的调用方式很相似!

#include <iostream>
#include "pugixml.hpp"
#include "pugiconfig.hpp"
#include <sys/time.h>
using namespace std;#define TEST_TIMES 10int main( void )
{pugi::xml_document doc;timeval starttime, endtime;double timeuse = 0.;double timeAverage = 0.;for( int i = 0; i < TEST_TIMES; ++i ){gettimeofday( &starttime, 0 );if( !doc.load_file( "/home/liuyc/DriverConfig.xml" ) ){cout << "failed in load xml file! _ " << i << endl;continue;}gettimeofday( &endtime, 0 );timeuse = 1000000. * (endtime.tv_sec - starttime.tv_sec) + endtime.tv_usec - starttime.tv_usec;timeuse *= 0.001 ;cout << " reading files costs : " << timeuse << "ms" << endl;timeAverage += timeuse;}timeAverage /= TEST_TIMES;cout << " \n** The end *******************\n    the average costs = " << timeAverage << "ms" << endl;return 0;
}

结果也正如博友所说,pugixml的效率甚至比rapidxml也明显快了不少!
这里写图片描述

总结

统计的时间如下(LINUX):

解析器消耗时间(ms)效率倍数(相对Qt)
Qt-QDomDocument25.851
TinyXml26.643.89
RapidXml2.719.54
pugixml1.5716.47

工作以来基本上都是在Qt下开发,深切体会到Qt的接口封装很完善易用,但不可避免的牺牲了一些效率(虽然没想到效率降低了这么多),相对的,tinyxml2和pugixml在接口上都与Qt非常相似,Pugixml的效率更是提升明显,所以目前xml的解析还是推荐Pugixml。后面我会继续仔细研究各类xml解析器的使用方法,再与大家分享!


http://chatgpt.dhexx.cn/article/sVIccMwO.shtml

相关文章

SlimXml和TinyXml,RapidXml的性能对比

July 18th, 2010 zero Leave a comment Go to comments 前两天有朋友问&#xff0c;我的SlimXml有没有和RapidXml对比过效率&#xff1f;我是第一次听说这个库&#xff0c;更不用说对比效率了&#xff0c;于是上他们网站看了下。 好家伙&#xff0c;居然号称比TinyXml快30&…

RapidXml使用

vs2017 rapidxml-1.13 1 RapidXml使用 1.1 创建xml #include <iostream> #include "rapidxml/rapidxml.hpp" #include "rapidxml/rapidxml_utils.hpp" #include "rapidxml/rapidxml_print.hpp"using namespace rapidxml;void crateXml(…

使用rapidxml解析xml

rapidxml是一个由C模板实现的高效率xml解析库&#xff0c;号称解析速度比tinyxml快50倍&#xff08;忽悠&#xff09;&#xff0c;并作为boost::property的内置解析库&#xff1a; 其独立版本的官网&#xff1a;http://rapidxml.sourceforge.net/ 使用rapidxml的方法tinyxml极其…

RapidXml读取并修改XML文件

RapidXml读取并修改XML文件 RapidXml介绍RapidXml读取与修改xml文件 RapidXml介绍 RapidXml尝试创建最快的XML解析器&#xff0c;同时保留可用性&#xff0c;可移植性和合理的W3C兼容性。它是一个用现代C 编写的原位解析器&#xff0c;解析速度接近strlen在同一数据上执行的函数…

c++开源库rapidxml介绍与示例

官方地址&#xff1a;http://rapidxml.sourceforge.net/ 官方手册&#xff1a;http://rapidxml.sourceforge.net/manual.html 也可以在github上下载到别人上传的rapidxml:https://github.com/dwd/rapidxml 1.头文件 一般我们用到的头文件只有这三个 #include "rapidx…

Ubuntu 18.04 LDAP认证

将ubuntu配置为通过ldap认证&#xff0c;使其成为ldap client&#xff0c;系统版本ubuntu 18.04。 一 软件安装 apt-get install ldap-utils libpam-ldap libnss-ldap nslcd配置1 配置2 配置3 配置4 配置5 配置6 配置7 配置8 配置8 二 认证方式中添加Ldap #auth-client-conf…

LDAP认证服务器

1.要准备的环境与软件(这里测试环境是Centos6.0-64位系统) alfresco-community-4.2.c-installer-linux-x64.bin (注: alfresco是一个免费开源系统&#xff0c;可以自己去下载) apache-tomcat-7.0.42.tar db-4.5.20.tar jdk-6u45-linux-x64.bin openldap-stable-20100219.tar ph…

Jumpserver部署+Ldap认证

内容导航 &#xff08;一&#xff09;jumpserver快速部署1&#xff0c;部署内容2&#xff0c;附上安装脚本3&#xff0c;解决github无法连接4&#xff0c;修改配置 &#xff08;二&#xff09;使用jumpserver1&#xff0c;登录信息2&#xff0c;添加主机3&#xff0c;web终端登…

SVN使用LDAP认证

前言 SVN架构 用户访问SVN服务器分为两个部分&#xff1a;认证与授权。 SVN内置了有认证与授权机制&#xff0c;其认证是通过SVN仓库内的passwd文件提供&#xff0c;但它是明文、静态的&#xff0c;不方便且安全性低。 SVN还支持外部的认证&#xff0c;比如SASL&#xff0c;…

ldap 认证 java_Java实现LDAP认证(上)

Baidu脑残&#xff0c;把原来的空间改得不伦不类。所以把一些技术的东西挪到这里。 我找到两种方法&#xff0c;大同小异&#xff0c;第一种是通过Spring&#xff0c;适合已经采用Spring的项目。 一般来说用户名和密码都是保存在数据库中。现在有这个需求&#xff0c;用户名和密…

Harbor 整合ldap认证

前提&#xff1a; ldap服务器已经安装&#xff1a;OpenLDAP安装部署 harbor服务器已经安装&#xff1a;Harbro v1.8.0部署 一、ldap组织结构 1、登录信息 2、查看用户信息 二、harbor配置 1、使用默认密码登录&#xff0c;admin/Harbor12345 2、认证模式 3、测试ldap服务器…

ldap认证 java_Java实现LDAP认证(上) | 学步园

Baidu脑残&#xff0c;把原来的空间改得不伦不类。所以把一些技术的东西挪到这里。 我找到两种方法&#xff0c;大同小异&#xff0c;第一种是通过Spring&#xff0c;适合已经采用Spring的项目。 一般来说用户名和密码都是保存在数据库中。现在有这个需求&#xff0c;用户名和密…

Zabbix 整合ldap认证

前提&#xff1a; zabbix部署完成&#xff1a;CentOS7.3 64位&#xff0c;搭建Zabbix3.4 ldap部署完成&#xff1a;OpenLDAP安装部署 一、LDAP服务端 1、ldap登录信息 2、查看ldap组织架构 3、添加zabbix默认用户Admin 二、Zabbix网页端 1、使用zabbix默认管理员用户登录 …

linux+配置ldap认证,Linux LDAP 认证配置

Linux通过LDAP方式&#xff0c;使用windows AD帐户登录linux shell&#xff0c;这个想法很cool吧。之前配置过一次&#xff0c;但过了太久忘记了&#xff0c;因此&#xff0c;今天把配 Linux通过LDAP方式&#xff0c;使用windows AD帐户登录linux shell&#xff0c;这个想法很c…

JumpServer 整合ldap认证

前提&#xff1a; ldap服务器已经安装&#xff1a;OpenLDAP安装部署 一、JumpServer安装 官网安装地址安装部署 - JumpServer 文档 1、一键部署 #系统版本 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) #默认会安装到 /opt/jumpser…

linux samba 配置ldap认证,Samba集成Ldap认证

Samba集成Ldap认证 1.基础安装 yum -y install samba-common samba samba-client smbldap-tools openldap-clients nss-pam-ldapd 2.配置authconfig-tui 执行命令 "authconfig-tui" 验证配置 # getent passwd zhangsan:x:6460:18650:zhangsan:/home/zhangsan:/bin/…

SVN集成LDAP认证

如何将 LDAP 的认证&#xff0c;集成到 SVN 中。集成的办法&#xff0c;目前是有两种&#xff1a;一种是 SVN 直接通过 SVN 端口直接访问的&#xff0c;通过 SASL 实现 LDAP 的认证&#xff1b;另一种是 SVN 通过 Apache 进行 HTTP 访问的用户&#xff0c;通过配置 Apache &…

zabbix配置ldap认证

zabbix配置ldap认证 环境&#xff1a; centos6.6 zabbix3.0.3 域控服务器&#xff1a;windows-active server 2008 需求&#xff1a; 公司越来越大&#xff0c;人越来越多&#xff0c;配置人员的账号密码很麻烦。 为了集中管理&#xff0c;整合公司的用户密码&#xff0c…

LDAP认证-ldap介绍

OpenLDAP简介 LDAP 全称轻量级目录访问协议&#xff0c;是一个运行在 TCP/IP 上的目录访问协议。LDAP实现 提供被称为目录服务的信息服务&#xff0c;可以看做是一张特殊的数据库系统。可以有效的 解决众多网络服务的用户账户问题&#xff0c;规定了统一的身份信息数据库、身份…

LDAP认证

注&#xff1a;本文由网络公开资料整理而来&#xff0c;如有错误&#xff0c;欢迎指正。 LDAP&#xff08;Lightweight Directory Access Protocol&#xff09;是目录服务&#xff08;DAP&#xff09;在TCP/IP上的实现&#xff0c;它是对X.500目录协议的移植&#xff0c;但是简…