Qt之QDomDocument操作xml文件-模拟ini文件存储

一、背景

不得不说Qt是一个很强大的类库,不管是做项目还是做产品,Qt自身封装的东西就已经非常全面了,我们今天的这篇文章就是模拟了Qt读写ini文件的一个操作,当然是由于一些外力原因,我们决定自己来完善下这个功能。好的,那么现在就让我们隆重的请出今天的主角–QSettings。这个类能干嘛呢?

答案就是:读写注册表或者读写ini文件,这对于我们做应用程序时记录一些可持久化数据非常有用。

二、QSettings访问ini文件

QSettings访问ini文件相对来说比较简单,我们只需要构造一个QSettings对象,传入文件名称和文件存储格式即可,如图1所示。但同时QSettings也有一些局限,如下:

1、QSettings的编码问题(QTBUG15543、QTBUG19552)

2、QSettings的key不能为中文

3、当在一个嵌套作用域多次构造QSettings时并设置了编码,此时访问文件设置的编码会失效

由于QSettings有一些限制,也就引出了我们这篇文章的内容,使用xml模拟ini文件,下面我们主要分析下怎么使用xml文件模拟ini文件,需要的接口并不多,读、写、新增和删除。

三、xml文件读写

读写xml文件的方式有很多,Qt提供了2种比较常用的方式:DOM和SAX,详情可以参看:Qt学习之XML读写操作小结。初次之外C++还提供了几种库用于操作xml文件,比如:libxml2、tinyXml等。

此处我们模拟的是QSettings读写ini文件,因此使用Qt自带的DOM方式读写xml,操作起来相对容易。

如图2所示,是我们xml文件操作类的几个重要接口和成员,前边4个公有接口分别对应。读、写、新增和删除;成员变量m_filePath表示加载的xml文件路径,m_mItemMap表示2级的ini文件结构

** 1、读xml文件**

void xmlOperate::readXml( const QString & filePath )
{
    if(filePath.isEmpty())
        return;

    QFile file(filePath);
    if(file.open(QFile::ReadOnly | QFile::Text) == false)
        return;

    QDomDocument domDocument;
    QString error;
    int row = 0, column = 0;
    if(domDocument.setContent(&file, false, &error, &row, &column) == false)
        return file.close();

    if(domDocument.isNull()) 
        return file.close();

    m_mItemMap.clear();

    QDomElement rootElement = domDocument.documentElement();
    QDomNodeList groupList = rootElement.childNodes();
    for(int i = 0; i < groupList.count(); ++i)
    {
        QDomNode groupNode = groupList.item(i);
        QDomElement groupElement = groupNode.toElement();
        QString groupName = groupElement.attribute("name");

        QMap<QString, QString> items;
        QDomNodeList itemList = groupElement.childNodes();
        for (int j = 0; j < itemList.count(); ++j)
        {
            QDomNode itemNode = itemList.item(j);
            QDomElement itemElement = itemNode.toElement();
            QString itemName = itemElement.attribute("name");
            QString itemText = itemElement.text();

            if (itemName.isEmpty())
            {
                items[QString::number(j)] = itemText;
            }
            else
            {
                items[itemName] = itemText;
            }
        }
        m_mItemMap[groupName] = items;
    }

    file.close();

    qDebug() << m_mItemMap;
}

2、保存xml文件

void xmlOperate::writeXml(const QString & filePath)
{
    QDomDocument domDocument;
    QString strHeader( "version=\"1.0\" encoding=\"UTF-8\"" );
    domDocument.appendChild( domDocument.createProcessingInstruction("xml", strHeader) );

    QDomElement root = domDocument.createElement("groups");
    domDocument.appendChild(root);

    for(auto iter = m_mItemMap.begin(); iter != m_mItemMap.end(); ++iter)
    {
        QDomElement groupNode = domDocument.createElement("group");
        groupNode.setAttribute("name", iter.key());

        QMap<QString, QString> items = iter.value();
        for (auto iter2 = items.begin(); iter2 != items.end(); ++iter2)
        {
            QString key = iter2.key();
            QString value = iter2.value();

            QDomElement itemNode = domDocument.createElement("item");
            itemNode.setAttribute("name", key);

            QDomText textNode = domDocument.createTextNode(value);
            itemNode.appendChild(textNode);

            groupNode.appendChild(itemNode);
        }
        root.appendChild(groupNode);
    }

    QFile file(filePath);
    if(file.open(QFile::WriteOnly | QFile::Text))
    {
        QTextStream out(&file);
        domDocument.save(out, 4);
        file.close();
    }
    qDebug() << m_mItemMap;
}

3、插入项

 bool xmlOperate::addItem( const QString & value, const QString & group, const QString & key )
{
    if (value.isEmpty() || group.isEmpty())
    {
        return false;
    }

    if (key.isEmpty())
    {
        int count = m_mItemMap[group].size();
        m_mItemMap[group][QString::number(count)] = value;
    }
    else
    {
        m_mItemMap[group][key] = value;
    }

    writeXml(m_filePath);

    return true;
}

4、删除项

bool xmlOperate::removeItem( const QString & value, const QString & group, const QString & key /*= ""*/ )
{
    if (value.isEmpty() || group.isEmpty())
    {
        return false;
    }

    if (key.isEmpty())
    {
        int count = m_mItemMap[group].size();
        if (count == 0)
        {
            return false;
        }
        
        auto iter = m_mItemMap[group].begin();
        while (iter != m_mItemMap[group].end())
        {
            if (iter.value() == value)
            {
                iter = m_mItemMap[group].erase(iter);
            }
            else
            {
                ++iter; 
            }
        }
    }
    else
    {
        m_mItemMap[group].remove(key);
    }

    writeXml(m_filePath);

    return true;
}

四、示例程序下载

如图3是测试代码生成的测试结果,group相当于ini文件中的一个分组,item表示分组中的一项

[ xml读写-xml模拟ini存储](https://download.csdn.net/download/qq_30392343/10539733)
如果您觉得文章不错,不妨给个 打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!




很重要–转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值