基于Qsetting的ini类

QT_INI

一、QT 自带INI (QSettings)
  1. ini格式

     [section]  #分组/节 
     ;注释      #注释/注解
     key=value  #键值对用等号连起来
     key2=123
      
     [section2]
     key=true
  2. QSettings

     //写入
     QSetting setting(path,QSettings::IniFormat);
     setting.setIniCodec("utf-8");
     qDebug()<<"write"<<path;
     setting.setValue("BB/AA","测试");
     setting.setValue("BB/BB",true);
     setting.setValue("BB/CC",123.7);
     setting.setValue("中文/中文","测试");
     //读取
     QSettings setting(path,QSetting::IniFormat);
     setting.setIniCodec("utf-8");
     qDebug()<<"read"<<path;
     qDebug()<<setting.value("BB/AA");
     qDebug()<<setting.value("BB/BB");
     qDebug()<<setting.value("BB/CC");
     qDebug()<<setting.value("中文/中文");
     qDebug()<<setting.value("None/AA");
     ​
  3. 问题

    注释:清除注释

    缓存:无

    编码:中文编码有问题

    长度:字符串长度有限制

二、自定义类
  1. EasyIni.h

 #pragma once
  
 #include <QObject>
 #include <QVariant>
 #include <QList>
  
 namespace Tool {
  
     class EasyIni : public QObject
     {
         Q_OBJECT
     public:
         //操作模式
         enum Mode
         {
             ReadOnly,
             WriteOnly,
             ReadWrite
         };
     public:
         explicit EasyIni(const QString &filepath,
                          EasyIni::Mode mode = EasyIni::ReadWrite,
                          QObject *parent = nullptr);
         ~EasyIni();
 ​
         //打印ini信息
         void dumpInfo() const;
         //分组列表
         QStringList groups() const;
         //分组内所有key
         QStringList keys(const QString &group) const;
         //获取值
         QVariant value(const QString &group, const QString &key) const;
         //设置值,group或key不存在则创建
         void setValue(const QString &group, const QString &key, const QVariant &value);
         //保存
         void save();
         //加载
         void load(const QString &filepath = QString());
 ​
     private:
         //判断当前路径是否可写
         bool isWritable() const;
         //解析ini文件
         void parse(const QString &filepath);
         //variant转str copy from qsettings
         static QString variantToString(const QVariant &v);
         //str转variant copy from qsettings
         static QVariant stringToVariant(const QString &s);
         //stringToVariant中用到的分割 copy from qsettings
         static QStringList splitArgs(const QString &s, int idx);
 ​
     private:
         //ini文件路径
         QString inipath;
         //操作模式
         EasyIni::Mode iniMode = EasyIni::ReadWrite;
 ​
         //【】数据结构
         //一行的数据
         struct IniRow{
             //是否有效,无效则仅保存在写入时恢复原格式
             bool isValid = false;
             //行key
             QString key;
             //行value
             QVariant value;
         };
         //一个分组的数据
         struct IniGroup{
             //是否为默认初始分组
             bool isHead = false;
             //分组名
             QString group;
             //分组行列表
             QList<IniRow> rows;
             //group key列表
             //无效行为空
             QList<QString> allkeys;
         };
         //ini分组列表
         struct IniData{
             //标记数据改变了,在析构时写入文件
             //或者主动写入文件
             bool change = false;
             //分组数据
             QList<IniGroup> datas;
             //group name列表
             //head和无效为空
             QList<QString> allgroups;
         };
 ​
         //ini数据
         IniData iniData;
     };
  
 }

  1. EasyIni.cpp

 #include "EasyIni.h"
 #include <QTextStream>
 #include <QDataStream>
 #include <QTemporaryFile>
 #include <QFileInfo>
 #include <QFile>
 #include <QDir>
 #include <QRect>
 #include <QSize>
 #include <QDebug>
  
 using namespace Tool;
  
 EasyIni::EasyIni(const QString &filepath, EasyIni::Mode mode, QObject *parent)
     : QObject(parent), inipath(filepath), iniMode(mode)
 {
     load();
 }
  
 EasyIni::~EasyIni()
 {
     save();
 }
  
 void EasyIni::dumpInfo() const
 {
     qDebug()<<"[dump ini info]";
     for(auto agroup:iniData.datas)
     {
         if(!agroup.isHead)
             qDebug()<<"[group]"<<agroup.group;
         for(auto arow:agroup.rows)
         {
             if(arow.isValid){
                 qDebug()<<"\t[key]"<<arow.key<<"[value]"<<arow.value;
             }else{
                 qDebug()<<"\t[unknown]"<<arow.key;
             }
         }
     }
     //qDebug()<<iniData.allgroups;
 }
  
 QStringList EasyIni::groups() const
 {
     auto result = iniData.allgroups;
     result.removeAll(QString());
     return result;
 }
  
 QStringList EasyIni::keys(const QString &group) const
 {
     QStringList key_list;
     int group_index = iniData.allgroups.indexOf(group);
     if(group.isEmpty()||group_index<0)
         return key_list;
     auto result = iniData.datas.at(group_index).allkeys;
     result.removeAll(QString());
     return result;
 }
  
 QVariant EasyIni::value(const QString &group, const QString &key) const
 {
     int group_index = iniData.allgroups.indexOf(group);
     if(group.isEmpty()||key.isEmpty()||group_index<0)
         return QVariant();
  
     int key_index = iniData.datas.at(group_index).allkeys.indexOf(key);
     if(key_index<0)
         return QVariant();
  
     return iniData.datas.at(group_index).rows.at(key_index).value;
 }
  
 void EasyIni::setValue(const QString &group, const QString &key, const QVariant &value)
 {
     if(group.isEmpty()||key.isEmpty())
         return;
     //如果是不存在的分组则创建
     int group_index = iniData.allgroups.indexOf(group);
     if(group_index<0){
         IniGroup ini_group;
         ini_group.isHead = false;
         ini_group.group = group;
         iniData.datas.push_back(ini_group);
         iniData.allgroups.push_back(group);
         group_index = iniData.allgroups.count()-1;
     }
     //如果不存在key则创建
     int key_index = iniData.datas.at(group_index).allkeys.indexOf(key);
     if(key_index<0){
         IniRow ini_row;
         ini_row.isValid = true;
         ini_row.key = key;
         //ini_row.value = value;
         iniData.datas[group_index].rows.push_back(ini_row);
         iniData.datas[group_index].allkeys.push_back(key);
         key_index = iniData.datas.at(group_index).allkeys.count()-1;
     }
     //插入这里有点疑问,就是
     iniData.datas[group_index].rows[key_index].value = value;
     //标记为已修改状态,在save时判断
     iniData.change = true;
 }
  
 void EasyIni::save()
 {
     //只读
     if(EasyIni::ReadOnly == iniMode)
         return;
  
     if(iniData.change && isWritable()){
         qDebug()<<"save ini"<<inipath;
         QFile file(inipath);
         //QIODevice::Text on windows endl=\r\n
         if(file.open(QIODevice::WriteOnly|QIODevice::Truncate|QIODevice::Text))
         {
             QTextStream t_s(&file);
             t_s.setCodec("utf-8");
             for(auto agroup:iniData.datas)
             {
                 if(!agroup.isHead){
                     t_s<<'['<<agroup.group<<']'<<endl;
                 }
  
                 for(auto arow:agroup.rows)
                 {
                     if(arow.isValid){
                         t_s<<arow.key<<'='<<variantToString(arow.value)<<endl; 
                    }else{ 
                        t_s<<arow.key<<endl; 
                    } 
                } 
            } 
            file.close(); 
        } 
    } 
} 
  
void EasyIni::load(const QString &filepath) 
{ 
    //保存当前的 
    save(); 
  
    iniData = IniData{ }; 
    const QString path = filepath.isEmpty()?inipath:filepath; 
    inipath = path; 
  
    QFile file(path); 
    if((EasyIni::WriteOnly == iniMode) || 
            !file.exists() || 
            !file.open(QIODevice::ReadOnly|QIODevice::Text)){ 
        return; 
    } 
  
    qDebug()<<"load ini"<<inipath; 
  
    IniData ini_data; 
    IniGroup ini_group; 
    IniRow ini_row; 
    QTextStream t_s(&file); 
    t_s.setCodec("utf-8"); 
    //qDebug()<<"all"<<t_s.readAll(); 
  
    //默认分组 
    ini_group.isHead=true; 
    while(!t_s.atEnd()){ 
        //去掉首尾空格 
        QString line_data=t_s.readLine().trimmed(); 
        //qDebug()<<"-- line:"<<line_data<<line_data.length(); 
  
        if(line_data.count()<3|| 
                line_data[0]==';'|| 
                line_data[0]=='#'){ 
            //长度小于三无效: a=0 or [a] 注释暂不考虑 
            ini_row.isValid=false; 
            ini_row.key=line_data; 
            ini_row.value.clear(); 
  
            ini_group.rows.push_back(ini_row); 
            ini_group.allkeys.push_back(QString()); 
            //qDebug()<<"invalid"<<line_data; 
        }else if(line_data[0]=='['&& 
                 line_data[line_data.length()-1]==']'){ 
            //分组 
            ini_data.datas.push_back(ini_group); 
            ini_data.allgroups.push_back(ini_group.group); 
  
            ini_group.isHead=false; 
            ini_group.group=line_data.mid(1,line_data.count()-2); 
  
            ini_group.rows.clear(); 
            ini_group.allkeys.clear(); 
            //qDebug()<<"group"<<ini_group.group; 
        }else{ 
            ini_row.isValid=false; 
            int split_index=line_data.indexOf('='); 
            if(split_index>0&&split_index<line_data.length()-1){ 
                QString key=line_data.mid(0,split_index).trimmed(); 
                QString value=line_data.mid(split_index+1,line_data.length()-split_index-1).trimmed(); 
                if(!key.isEmpty()&&!value.isEmpty()){ 
                    ini_row.isValid=true; 
                    ini_row.key=key; 
                    ini_row.value=stringToVariant(value); 
  
                    ini_group.rows.push_back(ini_row); 
                    ini_group.allkeys.push_back(key); 
                    //qDebug()<<"key-value"<<key<<value; 
                } 
            } 
            if(!ini_row.isValid){ 
                ini_row.key=line_data; 
                ini_row.value.clear(); 
  
                ini_group.rows.push_back(ini_row); 
                ini_group.allkeys.push_back(QString()); 
                //qDebug()<<"invalid"<<line_data; 
            } 
        } 
    } 
    file.close(); 
  
    //最后一个分组的数据 
    if(ini_group.isHead||(ini_data.allgroups.count()>0&&ini_group.isHead!=true)){ 
        ini_data.datas.push_back(ini_group); 
        ini_data.allgroups.push_back(ini_group.group); 
    } 
  
    iniData = ini_data; 
} 
  
bool EasyIni::isWritable() const 
{ 
    bool result=false; 
    QFileInfo fileinfo(inipath); 
    if(fileinfo.exists()){ 
        QFile file(inipath); 
        result=file.open(QFile::ReadWrite); 
        file.close(); 
    }else{ 
        QDir dir(fileinfo.absolutePath()); 
        if(dir.exists()||dir.mkpath(dir.absolutePath())){ 
            //临时文件 
            QTemporaryFile file(inipath); 
            result=file.open(); 
            file.close(); 
        } 
    } 
    return result; 
} 
  
QString EasyIni::variantToString(const QVariant &v) 
{ 
    QString result; 
  
    switch (v.type()) { 
    case QVariant::Invalid: 
        result = QLatin1String("@Invalid()"); 
        break; 
  
    case QVariant::ByteArray: { 
        QByteArray a = v.toByteArray(); 
        result = QLatin1String("@ByteArray(") 
                + QLatin1String(a.constData(), a.size()) 
                + QLatin1Char(')'); 
        break; 
    } 
  
    case QVariant::String: 
    case QVariant::LongLong: 
    case QVariant::ULongLong: 
    case QVariant::Int: 
    case QVariant::UInt: 
    case QVariant::Bool: 
    case QVariant::Double: 
    case QVariant::KeySequence: { 
        result = v.toString(); 
        if (result.contains(QChar::Null)) 
            result = QLatin1String("@String(") + result + QLatin1Char(')'); 
        else if (result.startsWith(QLatin1Char('@'))) 
            result.prepend(QLatin1Char('@')); 
        break; 
    } 
#ifndef QT_NO_GEOM_VARIANT 
    case QVariant::Rect: { 
        QRect r = qvariant_cast<QRect>(v); 
        result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height()); 
        break; 
    } 
    case QVariant::Size: { 
        QSize s = qvariant_cast<QSize>(v); 
        result = QString::asprintf("@Size(%d %d)", s.width(), s.height()); 
        break; 
    } 
    case QVariant::Point: { 
        QPoint p = qvariant_cast<QPoint>(v); 
        result = QString::asprintf("@Point(%d %d)", p.x(), p.y()); 
        break; 
    } 
#endif // !QT_NO_GEOM_VARIANT 
  
    default: { 
#ifndef QT_NO_DATASTREAM 
        QDataStream::Version version; 
        const char *typeSpec; 
        if (v.type() == QVariant::DateTime) { 
            version = QDataStream::Qt_5_6; 
            typeSpec = "@DateTime("; 
        } else { 
            version = QDataStream::Qt_4_0; 
            typeSpec = "@Variant("; 
        } 
        QByteArray a; 
        { 
            QDataStream s(&a, QIODevice::WriteOnly); 
            s.setVersion(version); 
            s << v; 
        } 
  
        result = QLatin1String(typeSpec) 
                + QLatin1String(a.constData(), a.size()) 
                + QLatin1Char(')'); 
#else 
        Q_ASSERT(!"stringToVariant: Cannot save custom types without QDataStream support"); 
#endif 
        break; 
    } 
    } 
  
    return result; 
} 
  
QVariant EasyIni::stringToVariant(const QString &s) 
{ 
    if (s.startsWith(QLatin1Char('@'))) { 
        if (s.endsWith(QLatin1Char(')'))) { 
            if (s.startsWith(QLatin1String("@ByteArray("))) { 
                return QVariant(s.midRef(11, s.size() - 12).toLatin1()); 
            } else if (s.startsWith(QLatin1String("@String("))) { 
                return QVariant(s.midRef(8, s.size() - 9).toString()); 
            } else if (s.startsWith(QLatin1String("@Variant(")) 
                       || s.startsWith(QLatin1String("@DateTime("))) { 
#ifndef QT_NO_DATASTREAM 
                QDataStream::Version version; 
                int offset; 
                if (s.at(1) == QLatin1Char('D')) { 
                    version = QDataStream::Qt_5_6; 
                    offset = 10; 
                } else { 
                    version = QDataStream::Qt_4_0; 
                    offset = 9; 
                } 
                QByteArray a = s.midRef(offset).toLatin1(); 
                QDataStream stream(&a, QIODevice::ReadOnly); 
                stream.setVersion(version); 
                QVariant result; 
                stream >> result; 
                return result; 
#else 
                Q_ASSERT(!"stringToVariant: Cannot load custom types without QDataStream support"); 
#endif 
#ifndef QT_NO_GEOM_VARIANT 
            } else if (s.startsWith(QLatin1String("@Rect("))) { 
                QStringList args = splitArgs(s, 5); 
                if (args.size() == 4) 
                    return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt())); 
            } else if (s.startsWith(QLatin1String("@Size("))) { 
                QStringList args = splitArgs(s, 5); 
                if (args.size() == 2) 
                    return QVariant(QSize(args[0].toInt(), args[1].toInt())); 
            } else if (s.startsWith(QLatin1String("@Point("))) { 
                QStringList args = splitArgs(s, 6); 
                if (args.size() == 2) 
                    return QVariant(QPoint(args[0].toInt(), args[1].toInt())); 
#endif 
            } else if (s == QLatin1String("@Invalid()")) { 
                return QVariant(); 
            } 
  
        } 
        if (s.startsWith(QLatin1String("@@"))) 
            return QVariant(s.mid(1)); 
    } 
  
    return QVariant(s); 
} 
  
QStringList EasyIni::splitArgs(const QString &s, int idx) 
{ 
    int l = s.length(); 
    Q_ASSERT(l > 0); 
    Q_ASSERT(s.at(idx) == QLatin1Char('(')); 
    Q_ASSERT(s.at(l - 1) == QLatin1Char(')')); 
  
    QStringList result; 
    QString item; 
  
    for (++idx; idx < l; ++idx) { 
        QChar c = s.at(idx); 
        if (c == QLatin1Char(')')) { 
            Q_ASSERT(idx == l - 1); 
            result.append(item); 
        } else if (c == QLatin1Char(' ')) { 
            result.append(item); 
            item.clear(); 
        } else { 
            item.append(c); 
        } 
    } 
    return result; 
}

相关推荐

  1. 基于Qsettingini

    2024-07-19 19:08:05       19 阅读
  2. 总结:Qt读写ini配置文件(QSettings)

    2024-07-19 19:08:05       27 阅读
  3. Qt QSettings 使用详解:跨平台配置管理

    2024-07-19 19:08:05       19 阅读
  4. QSet使用详解

    2024-07-19 19:08:05       26 阅读
  5. 基于JacksonJson工具

    2024-07-19 19:08:05       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-19 19:08:05       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-19 19:08:05       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-19 19:08:05       58 阅读
  4. Python语言-面向对象

    2024-07-19 19:08:05       69 阅读

热门阅读

  1. redhat 7服务管理

    2024-07-19 19:08:05       17 阅读
  2. Hystrix参数踩坑

    2024-07-19 19:08:05       22 阅读
  3. redis消息队列

    2024-07-19 19:08:05       15 阅读
  4. UpdateFaculty

    2024-07-19 19:08:05       20 阅读
  5. LC-3 汇编语言实现简易四子棋

    2024-07-19 19:08:05       18 阅读
  6. 浅谈:网络协议及网络连接

    2024-07-19 19:08:05       19 阅读
  7. 带有致命Bug的B-树代码(用C++/Python/Rust还原)

    2024-07-19 19:08:05       20 阅读
  8. 无极与有极电容的区别

    2024-07-19 19:08:05       20 阅读
  9. Flutter 中的基本数据类型:num、int 和 double

    2024-07-19 19:08:05       18 阅读
  10. Docker 常用命令详解

    2024-07-19 19:08:05       25 阅读
  11. 将AWS RDS MySQL实例从存储未加密改为加密的方案

    2024-07-19 19:08:05       24 阅读
  12. C++设计模式

    2024-07-19 19:08:05       18 阅读
  13. 【React】使用 antd 加载组件实现 iframe 的加载效果

    2024-07-19 19:08:05       22 阅读