Qt基礎之配置文件(QSettings)


在項目開發中,配置文件通常分為三種:ini文件、xml文件和json文件,個人認為三種文件的區別在於:ini文件記錄方便、格式簡單但不便於擴展;xml文件和json文件擴展性強,能夠記錄更復雜的配置文件,但格式相對復雜,特別是**對重復項的記錄有優勢**。因此,在選擇配置文件時,如文件內容較少,無(少)重復記錄項,可選擇ini文件,若文件內容多、邏輯層次復雜、需要重復記錄多組數據或者后期后期可能需要擴展多層關系,可選擇xml或json文件。

1.INI文件

Qt通過QSettings類讀寫ini文件(但是QSetting還可以讀取其它類型的配置文件,例如:注冊表)頭文件:QSetting.h,QSetting讀寫ini文件的步驟為:
    * 通過路徑名稱打開文件並設定為ini文件格式
    * 讀/寫數據
    * 關閉文件,刪除句柄


Qt讀文件示例如下:

//打開文件並指定為ini格式
QSettings* configIni = new QSettings(file_path, QSettings::IniFormat);
QString qTemp = "";
//讀指定節點的指定數據,其中“Log”為節點,save_days為具體數據項
logDays = configIni->value("Log/save_days").toInt();
qTemp = configIni->value("Log/print_debug").toString();
printDbgLog = qTemp.compare("true", Qt::CaseInsensitive) == 0 ? true : false;
//刪除指針,此處未關聯父對象,必須手動刪除,否則有內存泄露風險
delete configIni;

Qt寫文件示例如下:

//打開文件
QSettings* configIni = new QSettings(filePath, QSettings::IniFormat);
QString qTemp = "";
//寫入數據,必須指定寫入節點和值
configIni->setValue("Public/remove_time", removeTime);     //定時任務執行時間
configIni->setValue("Log/save_days", logDays);             //日志保存天數
      configIni->setValue("Log/print_debug", "true");
else
      configIni->setValue("Log/print_debug", "false");
delete  configIni;

2.XML文件

Qt有多種方法讀取xml文件,有人在網上總結了幾種方式,具體看這里,我使用的是DOM的方式,這種方式的有點在於理解簡單,讀寫完全按照xml文件的層級操作即可;缺點則是需要將文件完全放入內存后才可讀寫,也就是說,對於非常大的xml文件,這不是一種理想的處理方式。使用DOM方式解析xml必須包含頭文件:<QtXml/qxml.h>和<QtXml/QDomComment>

DOM方式讀取xml文件的過程如下

  a.讀取文件內容並整體轉換成DOM結構樹存儲於內存中;

  b.按結構解析節點數據;

  c.清理內存

  具體示例代碼:

//xml類型配置文件讀寫
bool ConfigFile::LoadXMLFile(QString file_path)
{
    bool bRet = true;
    //step1:讀文件
    QFile file(file_path);
    if (!file.open(QFile::ReadOnly))
    {
        errMsg = QString("文件打開失敗,%1").arg(file.errorString());
        return false;
    }

    QString errorStr;
    int errorLine;
    int errorColumn;

    //qml數據存儲格式
    QDomDocument doc;
    //step2:轉換成xml數據格式
    if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
    {
        errMsg = QString("QML解析錯誤,%1,%2,%3").arg(errorStr)
             .arg(QString::number(errorLine)).arg(QString::number(errorColumn));
         file.close();
         return false;
    }
    //此時已經不需要文件句柄,可關閉
    file.close();

    //根節點元素
    QDomElement root = doc.documentElement();

 #pragma region "每個文件不一樣,由此處開始修改"
     //簡單節點結構
     QDomElement parts = root.firstChildElement("module");
     if (parts.isNull())
     {
         bRet = false;
         errMsg = "文件格式異常,未發現[module]節點";
         goto _RET;
      }
     else
     {
         //ups
         QDomElement temp = parts.firstChildElement("ups");
         if (temp.isNull())
          {
              bRet = false;
              errMsg = "文件格式異常,未發現[model/ups]節點";
              goto _RET;
          }
          else
          {
              QString st = temp.text();
              if (st.compare("true") == 0)
                  modeUPS = true;
              else
                  modeUPS = false;
          }


      //多重嵌套、重復結構
      {
         parts = root.firstChildElement("processor_monitor");
         if (parts.isNull())
         {
             bRet = false;
             errMsg = QString("文件格式異常,未發現[processor_monitor]節點");
             goto _RET;
         }
         else
         {
               //循環解析,獲取測量點數據
              QDomElement subElement = parts.firstChildElement();
              while (!subElement.isNull())
              {
                  if (subElement.tagName().compare("processor") == 0)
                  {
                     ProcessorInfo tempValue;
                      if (!GetProcessorInfo(subElement, tempValue))
                      {
                          bRet = false;
                          errMsg = QString("進程監控節點解析失敗,%1").arg(errMsg);
                          goto _RET;
                      }
                      else
                          vecProcessorInfo.push_back(tempValue);
                  }

                  subElement = subElement.nextSiblingElement();
              }
          }
      }

 #pragma endregion

  _RET:
      doc.clear();
      return bRet;
}
View Code

DOM方式寫入xml文件的過程如下

  a.創建DOM結構樹根節點

  b.在根節點上按層級插入數據節點

  c.將內存中的DOM數據結構轉化為符合xml格式的字符串

  d.將字符串寫入文件

  具體示例代碼:

bool ConfigFile::SaveXMLFile()
{
    bool bRet = true;
    QFile file(filePath);
    QDomDocument doc;           //xml結構

    //以只寫入方式打開,並且打開時清空原來內容
    if (!file.open(QFile::WriteOnly | QFile::Truncate))
    {
        errMsg = QString("文件打開失敗,%1").arg(file.errorString());
        return false;
    }

    //寫入xml頭部
    QDomProcessingInstruction instruction; //添加處理命令
    instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);

    //添加根節點
    QDomElement root = doc.createElement("root");
    doc.appendChild(root);

#pragma region  跟隨配置文件記錄項改變
    QString strTemp = "";
    QDomText text;

    //寫入model節點
    {
        //ups
        QDomElement model = doc.createElement("module");
        QDomElement subNode = doc.createElement("ups");
        if (modeUPS)
            strTemp = "true";
        else
            strTemp = "false";
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        model.appendChild(subNode);

        //process
        subNode = doc.createElement("process");
        if (modeUPS)
            strTemp = "true";
        else
            strTemp = "false";
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        model.appendChild(subNode);
        root.appendChild(model);
    }


    //寫入Processor_monitor節點數據
    {
        QDomElement eProcessorList = doc.createElement("processor_monitor");

        for (auto it : vecProcessorInfo)
        {
            QDomElement eProcessor = doc.createElement("processor");

            //name
            QDomElement eSub = doc.createElement("name");
            text = doc.createTextNode(it.processorName);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //path
            eSub = doc.createElement("path");
            text = doc.createTextNode(it.processroPath);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //autoStart
            if (it.isRestart)
                strTemp = "true";
            else
                strTemp = "false";
            eSub = doc.createElement("autostart");
            text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //property
            strTemp = QString::number(it.stopProprity);
            eSub = doc.createElement("proprity");
            text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            eProcessorList.appendChild(eProcessor);
        }

        root.appendChild(eProcessorList);
    }

#pragma endregion

    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4); //縮進4格
    file.close();
    doc.clear()
    return true;
}
View Code

DOM方式處理xml文件比較好理解:按照各個節點的實際從屬關系插入/讀取即可,但是對內存的使用效率偏低。

3.JSON文件

  在我的項目經驗中,並沒有碰到過用json文件作為配置文件的情況,個人理解,json多用於不同程序間的數據交互,相較與xml,它的冗余信息更少,但又不會丟失數據間邏輯關系,同時便於擴展,因此,個人認為,json數據更適合作為通信數據的載體而不是配置文件。

  Qt處理JSON數據的類為QJsonObject、QJsonDocument、QJsonValue、QJsonParseError,頭文件與類名相同。JSON文件的處理與XML文件類似,讀取文件的過程為:a.從文件讀取數據;b.將字符型數據轉換為JSON格式數據並存在內存;c.從內存結構中讀取數據。寫文件的過程為:a.創建內存結構;b.插入數據;c.將數據轉化為字符型數據並存儲到文本中。

以下代碼展示了創建簡單json數據的過程,最終結果QstrJson為QByteArray結構:

QJsonObject json;
json.insert("CMD", QString("GRM"));
json.insert("RM", macro_addr);

QJsonDocument document;
document.setObject(json);
QstrJson = document.toJson(QJsonDocument::Compact);
if (G_INIFILE->printDbgLog)
    LOG(INFO) << "發包數據:" << QstrJson.toStdString();

以下代碼展示解析簡單json的過程,其中,原始數據保存在qstrRecv中

//解析數據
    QJsonParseError parseJsonErr;
    QJsonDocument document = QJsonDocument::fromJson(qstrRecv.toUtf8(), &parseJsonErr);
    if (!(parseJsonErr.error == QJsonParseError::NoError))
    {
        errMsg = QString("解析json文件錯誤,%1").arg(parseJsonErr.errorString());
        return false;
    }

    QJsonObject jsonObject = document.object();

    //CMD
    QString temp = jsonObject["CMD"].toString();
    if (temp.compare("GRM") != 0)
    {
        errMsg = "收包命令錯誤";
        return false;
    }

    //RM
    int addrIn = jsonObject["RM"].toInt();
    if (addrIn != macro_addr)
    {
        errMsg = "收包Macro地址錯誤";
        return false;
    }

    //RET
    if (jsonObject.contains("RET"))
    {
        QJsonValue jsonValueList = jsonObject.value("RET");
        QJsonObject item = jsonValueList.toObject();

        //ERR
        int errCode = item["ERR"].toInt();
        if (errCode != 0)
        {
            //MSG
            QString err = item["MSG"].toString();
            errMsg = QString("CNC反饋錯誤,錯誤碼:%1,詳情:%2").arg(errCode).arg(err);
            return false;
        }
    }

    //DATA
    if (jsonObject.contains("DATA"))
    {
        QJsonValue jsonValueList = jsonObject.value("DATA");
        QJsonObject item = jsonValueList.toObject();
        macro_value = item["RMV"].toDouble();
    }
View Code

4.總結

為了以后少造輪子,根據自己的使用經驗,我自己定義了一個配置文件讀寫類,可以讀寫ini文件和xml文件,具體如下:

#pragma once
#include <qsettings.h>
#include <qstring.h>
#include <qdir.h>
#include "qcoreapplication.h"
#include <mutex>
#include "DataDefine.h"
#include "vector"
#include <QtXml/qxml.h>
#include <QtXml/QDomDocument>

class CLock
{
private:
    std::mutex mux;
public:
    CLock() {}

    ~CLock() {}

    void Lock()
    {
        mux.lock();
    }

    void Unlock()
    {
        mux.unlock();
    }
};

class ConfigFile
{
public:
    ~ConfigFile();

private://禁用賦值初始化
    ConfigFile();
    ConfigFile(const ConfigFile&);
    ConfigFile& operator=(const ConfigFile&);

    static std::shared_ptr<ConfigFile> m_pInstance;
    static CLock m_lock;
public:
    //錯誤信息
    QString errMsg;
    //日志存儲天數(天)
    int logDays;
    //是否打印調試日志
    bool printDbgLog;
    //定時任務執行時間
    QString removeTime;

public://UPS相關配置
    bool modeUPS;            //是否啟用UPS模塊
    bool modeProcess;        //是否啟用process模塊
    QString supplier;        //供應商
    QString model;            //型號
    QString serialName;        //com口
    int shutdownPCDelay;    //關閉電腦延時時間
    //進程監控相關配置
    std::vector<ProcessorInfo> vecProcessorInfo;

private:
    //文件類別
    int fileType;    
    //文件路徑
    QString filePath;    
    //當前exe運行路徑
    //QString iniPath;
    //exe目錄
    QString exeDir;
public:
    //獲取句柄,懶漢單例模式,雙重鎖,線程安全
    static std::shared_ptr<ConfigFile> getInstance()
    {
        if (nullptr == m_pInstance)
        {
            m_lock.Lock();
            if (nullptr == m_pInstance)
            {
                m_pInstance = std::shared_ptr<ConfigFile>(new ConfigFile);
            }
            m_lock.Unlock();
        }

        return m_pInstance;
    }

    //文件類別
    enum
    {
        INI_FILE = 0,        //.ini的配置文件
        XML_FILE            //.xml的配置文件
    };

    //讀取配置文件
    bool LoadConfigFile(QString file_path, int file_type);
    //寫入配置文件
    bool SaveConfigFile();

    //獲取exe所在目錄
    QString GetExeDir(void);
private:
    //ini文件讀寫操作
    bool LoadIniFile(QString file_path);
    bool SaveIniFile();

    //xml文件讀寫操作
    bool LoadXMLFile(QString file_path);
    bool SaveXMLFile();

public://按實際配置文件寫
    //獲取供應商
    QString GetSupplier();
    //獲取UPS型號
    QString GetUPSModel();
    //獲取串口名稱
    QString GetSerialName();
    //獲取延時時間
    int GetDelayMin();

private:
    //讀取一個進程的參數
    bool GetProcessorInfo(const QDomElement &src,ProcessorInfo &value);
};

#define G_CONFIG ConfigFile::getInstance()

ConfigFile.h
View Code
#include "ConfigFile.h"

# pragma execution_character_set("utf-8")

std::shared_ptr<ConfigFile> ConfigFile::m_pInstance = nullptr;
CLock ConfigFile::m_lock;

ConfigFile::ConfigFile()
{
    //日志存儲天數
    logDays = 7;
    //是否打印調試日志
    printDbgLog = false;

    exeDir = QCoreApplication::applicationDirPath();

    fileType = XML_FILE;
}

ConfigFile::ConfigFile(const ConfigFile&)
{

}

ConfigFile::~ConfigFile()
{

}

//讀取配置文件
bool ConfigFile::LoadConfigFile(QString file_path, int file_type)
{
    filePath = file_path;
    fileType = file_type;

    if (file_type == INI_FILE)
        return LoadIniFile(file_path);
    else if (file_type == XML_FILE)
        return LoadXMLFile(file_path);
    else
    {
        errMsg = "文件類型設置錯誤";
        return false;
    }

    return false;
}

//寫入配置文件
bool ConfigFile::SaveConfigFile()
{
    if (fileType == XML_FILE)
        return SaveXMLFile();
    else
        return SaveIniFile();
   
    return false;
}

//ini類型配置文件讀寫
bool ConfigFile::LoadIniFile(QString file_path)
{
    filePath = file_path;

    QSettings* configIni = new QSettings(file_path, QSettings::IniFormat);
    QString qTemp = "";
    //log
    logDays = configIni->value("Log/save_days").toInt();
    qTemp = configIni->value("Log/print_debug").toString();
    printDbgLog = qTemp.compare("true", Qt::CaseInsensitive) == 0 ? true : false;

    //定時任務時間
    removeTime = configIni->value("Public/remove_time").toString();

    //UPS參數
    {
        //供應商
        supplier = configIni->value("UPS/supplier").toString();

        //型號
        model = configIni->value("UPS/model").toString();

        //com口
        serialName = configIni->value("UPS/com").toString();

        //關閉電腦延時時間
        shutdownPCDelay = configIni->value("UPS/shutdown_pc_delay").toInt();
    }

    //進程參數
    {

    }
   
    delete configIni;

    return true;
}

bool ConfigFile::SaveIniFile()
{
    QSettings* configIni = new QSettings(filePath, QSettings::IniFormat);
    QString qTemp = "";

    //Public
    configIni->setValue("Public/remove_time", removeTime);     //定時任務執行時間

    //Log
    configIni->setValue("Log/save_days", logDays);             //日志保存天數
    
    if (printDbgLog)                                           //打印調試日志
        configIni->setValue("Log/print_debug", "true");
    else
        configIni->setValue("Log/print_debug", "false");

    /*
    //KValue
    configIni->setValue("KValue/part_name", qmlK.kPartName);              //零件名
    configIni->setValue("KValue/prg_num", qmlK.kCurPrgNum);               //程序編號
    configIni->setValue("KValue/param_name", qmlK.kParamName);            //被測參數名稱
    configIni->setValue("KValue/standard_value", qmlK.kStandardValue);    //名義值
    configIni->setValue("KValue/lower_deviation", qmlK.kLowerDeviation);  //下公差
    configIni->setValue("KValue/upper_deviation", qmlK.kUpperDeviation);  //上公差
    configIni->setValue("KValue/measure_value", qmlK.kMeasureValue);      //測量值
    configIni->setValue("KValue/measure_time", qmlK.kMeasureTime);        //測量時間
    configIni->setValue("KValue/work_station", qmlK.kWorkStation);        //治具
    
    //CNC
    configIni->setValue("CNC/ip", cncParam.ip);                      //CNC IP地址
    configIni->setValue("CNC/port", cncParam.port);                  //CNC IP地址
    configIni->setValue("CNC/left_x1", cncParam.leftMain.x);         //左治具主孔X軸
    configIni->setValue("CNC/left_y1", cncParam.leftMain.y);         //左治具主孔Y軸
    configIni->setValue("CNC/left_z1", cncParam.leftMain.z);        //左治具主孔Z軸
    configIni->setValue("CNC/left_x2", cncParam.leftSub.x);          //左治具副孔X軸
    configIni->setValue("CNC/left_y2", cncParam.leftSub.y);          //左治具副孔Y軸
    configIni->setValue("CNC/left_z2", cncParam.leftSub.z);          //左治具副孔Z軸
    configIni->setValue("CNC/left_x3", cncParam.leftThird.x);        //左治具溫水孔X軸
    configIni->setValue("CNC/left_y3", cncParam.leftThird.y);        //左治具溫水孔Y軸
    configIni->setValue("CNC/left_z3", cncParam.leftThird.z);        //左治具溫水孔Z軸
    configIni->setValue("CNC/right_x1", cncParam.rightMain.x);       //右治具主孔X軸
    configIni->setValue("CNC/right_y1", cncParam.rightMain.y);       //右治具主孔Y軸
    configIni->setValue("CNC/right_z1", cncParam.rightMain.z);       //右治具主孔Z軸
    configIni->setValue("CNC/right_x2", cncParam.rightSub.x);        //右治具副孔X軸
    configIni->setValue("CNC/right_y2", cncParam.rightSub.y);        //右治具副孔Y軸
    configIni->setValue("CNC/right_z2", cncParam.rightSub.z);        //右治具副孔Z軸
    configIni->setValue("CNC/right_x3", cncParam.rightThird.x);      //右治具溫水孔X軸
    configIni->setValue("CNC/right_y3", cncParam.rightThird.y);      //右治具溫水孔Y軸
    configIni->setValue("CNC/right_z3", cncParam.rightThird.z);      //右治具溫水孔Z軸

    //Folder
    configIni->setValue("Folder/qml_src", qstrQMLSrc);      //QML源文件地址
    configIni->setValue("Folder/qml_dst", qstrQMLDst);      //QML目標文件地址

    //section_main
    configIni->setValue("Section_main/alarm_lower_limit_X", limit[0].alarmLowerLimit);
    configIni->setValue("Section_main/alarm_upper_limit_X", limit[0].alarmUpperLimit);
    configIni->setValue("Section_main/avoid_lower_limit_X", limit[0].avoidLowerLimit);
    configIni->setValue("Section_main/avoid_upper_limit_X", limit[0].avoidUpperLimit);

    configIni->setValue("Section_main/alarm_lower_limit_Y", limit[1].alarmLowerLimit);
    configIni->setValue("Section_main/alarm_upper_limit_Y", limit[1].alarmUpperLimit);
    configIni->setValue("Section_main/avoid_lower_limit_Y", limit[1].avoidLowerLimit);
    configIni->setValue("Section_main/avoid_upper_limit_Y", limit[1].avoidUpperLimit);

    configIni->setValue("Section_main/alarm_lower_limit_Z", limit[2].alarmLowerLimit);
    configIni->setValue("Section_main/alarm_upper_limit_Z", limit[2].alarmUpperLimit);
    configIni->setValue("Section_main/avoid_lower_limit_Z", limit[2].avoidLowerLimit);
    configIni->setValue("Section_main/avoid_upper_limit_Z", limit[2].avoidUpperLimit);

    //Section_sub
    configIni->setValue("Section_sub/alarm_lower_limit_X", limit[3].alarmLowerLimit);
    configIni->setValue("Section_sub/alarm_upper_limit_X", limit[3].alarmUpperLimit);
    configIni->setValue("Section_sub/avoid_lower_limit_X", limit[3].avoidLowerLimit);
    configIni->setValue("Section_sub/avoid_upper_limit_X", limit[3].avoidUpperLimit);

    configIni->setValue("Section_sub/alarm_lower_limit_Y", limit[4].alarmLowerLimit);
    configIni->setValue("Section_sub/alarm_upper_limit_Y", limit[4].alarmUpperLimit);
    configIni->setValue("Section_sub/avoid_lower_limit_Y", limit[4].avoidLowerLimit);
    configIni->setValue("Section_sub/avoid_upper_limit_Y", limit[4].avoidUpperLimit);

    configIni->setValue("Section_sub/alarm_lower_limit_Z", limit[5].alarmLowerLimit);
    configIni->setValue("Section_sub/alarm_upper_limit_Z", limit[5].alarmUpperLimit);
    configIni->setValue("Section_sub/avoid_lower_limit_Z", limit[5].avoidLowerLimit);
    configIni->setValue("Section_sub/avoid_upper_limit_Z", limit[5].avoidUpperLimit);

    //Section_third
    configIni->setValue("Section_third/alarm_lower_limit_X", limit[6].alarmLowerLimit);
    configIni->setValue("Section_third/alarm_upper_limit_X", limit[6].alarmUpperLimit);
    configIni->setValue("Section_third/avoid_lower_limit_X", limit[6].avoidLowerLimit);
    configIni->setValue("Section_third/avoid_upper_limit_X", limit[6].avoidUpperLimit);

    configIni->setValue("Section_third/alarm_lower_limit_Y", limit[7].alarmLowerLimit);
    configIni->setValue("Section_third/alarm_upper_limit_Y", limit[7].alarmUpperLimit);
    configIni->setValue("Section_third/avoid_lower_limit_Y", limit[7].avoidLowerLimit);
    configIni->setValue("Section_third/avoid_upper_limit_Y", limit[7].avoidUpperLimit);

    configIni->setValue("Section_third/alarm_lower_limit_Z", limit[8].alarmLowerLimit);
    configIni->setValue("Section_third/alarm_upper_limit_Z", limit[8].alarmUpperLimit);
    configIni->setValue("Section_third/avoid_lower_limit_Z", limit[8].avoidLowerLimit);
    configIni->setValue("Section_third/avoid_upper_limit_Z", limit[8].avoidUpperLimit);
    */

    delete  configIni;
    
    return true;
}

//xml類型配置文件讀寫
bool ConfigFile::LoadXMLFile(QString file_path)
{
    bool bRet = true;
    //step1:讀文件
    QFile file(file_path);
    if (!file.open(QFile::ReadOnly))
    {
        errMsg = QString("文件打開失敗,%1").arg(file.errorString());
        return false;
    }

    QString errorStr;
    int errorLine;
    int errorColumn;

    //qml數據存儲格式
    QDomDocument doc;
    //step2:轉換成xml數據格式
    if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
    {
        errMsg = QString("QML解析錯誤,%1,%2,%3").arg(errorStr)
            .arg(QString::number(errorLine)).arg(QString::number(errorColumn));
        file.close();
        return false;
    }
    file.close();

    //根節點元素    
    QDomElement root = doc.documentElement();

#pragma region "每個文件不一樣,由此處開始修改"
    //mode
    QDomElement parts = root.firstChildElement("module");
    if (parts.isNull())
    {
        bRet = false;
        errMsg = "文件格式異常,未發現[module]節點";
        goto _RET;
    }
    else
    {
        //ups
        QDomElement temp = parts.firstChildElement("ups");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[model/ups]節點";
            goto _RET;
        }
        else
        {
            QString st = temp.text();
            if (st.compare("true") == 0)
                modeUPS = true;
            else
                modeUPS = false;
        }
           
        //process
        temp = parts.firstChildElement("process");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[model/process]節點";
            goto _RET;
        }
        else
        {
            QString st = temp.text();
            if (st.compare("true") == 0)
                modeProcess = true;
            else
                modeProcess = false;
        }
    }

    //log節點
    parts = root.firstChildElement("log");
    if (parts.isNull())
    {
        bRet = false;
        errMsg = "文件格式異常,未發現[QML]節點";
        goto _RET;
    }
    else
    {
        //save_days
        QDomElement temp = parts.firstChildElement("save_days");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[log/save_days]節點";
            goto _RET;
        }
        else
            logDays = temp.text().toInt();

        //print_debug
        temp = parts.firstChildElement("print_debug");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[log/print_debug]節點";
            goto _RET;
        }
        else
        {
            QString ss = temp.text();
            if (ss.compare("true") == 0 || ss.compare("TRUE") == 0)
                printDbgLog = true;
            else
                printDbgLog = false;
        }            
    }

    //Public節點
    parts = root.firstChildElement("Public");
    if (parts.isNull())
    {
        bRet = false;
        errMsg = QString("文件格式異常,未發現[Public]節點");
        goto _RET;
    }
    else
    {
        //remote_time
        QDomElement temp = parts.firstChildElement("remote_time");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[Public/remote_time]節點";
            goto _RET;
        }
        else
            removeTime = temp.text();
    }

    //UPS節點
    parts = root.firstChildElement("UPS");
    if (parts.isNull())
    {
        bRet = false;
        errMsg = QString("文件格式異常,未發現[UPS]節點");
        goto _RET;
    }
    else
    {
        //supplier
        QDomElement temp = parts.firstChildElement("supplier");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[UPS/supplier]節點";
            goto _RET;
        }
        else
            supplier = temp.text();

        //model
        temp = parts.firstChildElement("model");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[UPS/model]節點";
            goto _RET;
        }
        else
            model = temp.text();

        //serialName
        temp = parts.firstChildElement("serialName");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[UPS/serialName]節點";
            goto _RET;
        }
        else
            serialName = temp.text();

        //shutdownPCDelay
        temp = parts.firstChildElement("shutdown_pc_delay");
        if (temp.isNull())
        {
            bRet = false;
            errMsg = "文件格式異常,未發現[UPS/shutdown_pc_delay]節點";
            goto _RET;
        }
        else
            shutdownPCDelay = temp.text().toInt();
    }

    //進程監控節點
    {
        parts = root.firstChildElement("processor_monitor");
        if (parts.isNull())
        {
            bRet = false;
            errMsg = QString("文件格式異常,未發現[processor_monitor]節點");
            goto _RET;
        }
        else
        {
              //循環解析,獲取測量點數據
            QDomElement subElement = parts.firstChildElement();
            while (!subElement.isNull())
            {
                if (subElement.tagName().compare("processor") == 0)
                {
                    ProcessorInfo tempValue;
                    if (!GetProcessorInfo(subElement, tempValue))
                    {
                        bRet = false;
                        errMsg = QString("進程監控節點解析失敗,%1").arg(errMsg);
                        goto _RET;
                    }
                    else
                        vecProcessorInfo.push_back(tempValue);
                }

                subElement = subElement.nextSiblingElement();
            }           
        }
    }

#pragma endregion

_RET:
    doc.clear();
    return bRet;
}

bool ConfigFile::SaveXMLFile()
{
    bool bRet = true;
    QFile file(filePath);
    QDomDocument doc;           //xml結構

    //以只寫入方式打開,並且打開時清空原來內容
    if (!file.open(QFile::WriteOnly | QFile::Truncate))
    {
        errMsg = QString("文件打開失敗,%1").arg(file.errorString());
        return false;
    }
   
    //寫入xml頭部
    QDomProcessingInstruction instruction; //添加處理命令
    instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);

    //添加根節點
    QDomElement root = doc.createElement("root");
    doc.appendChild(root);

#pragma region  跟隨配置文件記錄項改變
    QString strTemp = "";
    QDomText text;

    //寫入model節點
    {
        //ups
        QDomElement model = doc.createElement("module");
        QDomElement subNode = doc.createElement("ups");
        if (modeUPS)
            strTemp = "true";
        else
            strTemp = "false";
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        model.appendChild(subNode);

        //process
        subNode = doc.createElement("process");
        if (modeUPS)
            strTemp = "true";
        else
            strTemp = "false";
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        model.appendChild(subNode);
        root.appendChild(model);
    }

    //寫入log節點數據
    {
        QDomElement log = doc.createElement("log");
        QDomElement subNode = doc.createElement("save_days");
        strTemp = QString::number(logDays);
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        log.appendChild(subNode);

        subNode = doc.createElement("print_debug");
        if (printDbgLog)
            strTemp = "true";
        else
            strTemp = "false";
        text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
        subNode.appendChild(text);
        log.appendChild(subNode);

        root.appendChild(log);
    }

    //寫入Public節點數據
    {
        QDomElement ePublic = doc.createElement("Public");
        QDomElement eRemoveTime = doc.createElement("remote_time");
        text = doc.createTextNode(removeTime);        //設置括號標簽中間的值
        eRemoveTime.appendChild(text);
        ePublic.appendChild(eRemoveTime);
        root.appendChild(ePublic);
    }

    //寫入UPS節點數據
    {
        QDomElement eUPS = doc.createElement("UPS");

        QDomElement eSub = doc.createElement("supplier");
        text = doc.createTextNode(supplier);        //設置括號標簽中間的值
        eSub.appendChild(text);
        eUPS.appendChild(eSub);

        eSub = doc.createElement("model");
        text = doc.createTextNode(model);        //設置括號標簽中間的值
        eSub.appendChild(text);
        eUPS.appendChild(eSub);

        eSub = doc.createElement("serialName");
        text = doc.createTextNode(serialName);        //設置括號標簽中間的值
        eSub.appendChild(text);
        eUPS.appendChild(eSub);

        eSub = doc.createElement("shutdown_pc_delay");
        text = doc.createTextNode(QString::number(shutdownPCDelay));        //設置括號標簽中間的值
        eSub.appendChild(text);
        eUPS.appendChild(eSub);

        root.appendChild(eUPS);
    }

    //寫入Processor_monitor節點數據
    {
        QDomElement eProcessorList = doc.createElement("processor_monitor");
      
        for (auto it : vecProcessorInfo)
        {
            QDomElement eProcessor = doc.createElement("processor");

            //name
            QDomElement eSub = doc.createElement("name");
            text = doc.createTextNode(it.processorName);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //path
            eSub = doc.createElement("path");
            text = doc.createTextNode(it.processroPath);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //autoStart
            if (it.isRestart)
                strTemp = "true";
            else
                strTemp = "false";
            eSub = doc.createElement("autostart");           
            text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            //property
            strTemp = QString::number(it.stopProprity);
            eSub = doc.createElement("proprity");
            text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
            eSub.appendChild(text);
            eProcessor.appendChild(eSub);

            eProcessorList.appendChild(eProcessor);
        }

        root.appendChild(eProcessorList);
    }

#pragma endregion

    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream, 4); //縮進4格
    file.close();
    doc.clear();
    return true;
}

//讀取一個進程的參數
bool ConfigFile::GetProcessorInfo(const QDomElement& src, ProcessorInfo& value)
{
    QDomElement subElement;

    //name
    subElement = src.firstChildElement("name");
    if (subElement.isNull())
    {
        errMsg = QString("[name]參數不存在");
        return false;
    }
    else
        value.processorName = subElement.text();

    //path
    subElement = src.firstChildElement("path");
    if (subElement.isNull())
    {
        errMsg = QString("[path]參數不存在");
        return false;
    }
    else
        value.processroPath = subElement.text();

    //autostart
    subElement = src.firstChildElement("autostart");
    if (subElement.isNull())
    {
        errMsg = QString("[autostart]參數不存在");
        return false;
    }
    else
    {
        QString strTemp = subElement.text();
        if (strTemp.compare("true") == 0 || strTemp.compare("TRUE") == 0)
            value.isRestart = true;
        else
            value.isRestart = false;
    }

    //property
    subElement = src.firstChildElement("proprity");
    if (subElement.isNull())
    {
        errMsg = QString("[proprity]參數不存在");
        return false;
    }
    else
    {
        QString strTemp = subElement.text();
        value.stopProprity = strTemp.toInt();
        if (value.stopProprity < 0 || value.stopProprity > 2)
            value.stopProprity = 2;
    }

    if (value.processorName.isEmpty())
    {
        errMsg = QString("進程名稱為空");
        return false;
    }

    if (value.processroPath.isEmpty())
    {
        errMsg = QString("進程路徑為空");
        return false;
    }

    return true;
}

//獲取供應商
QString ConfigFile::GetSupplier() { return supplier; }

//獲取UPS型號
QString ConfigFile::GetUPSModel() { return model; }

//獲取串口名稱
QString ConfigFile::GetSerialName() { return serialName; }

//獲取延時時間
int ConfigFile::GetDelayMin() { return shutdownPCDelay; }

QString ConfigFile::GetExeDir(void) { return exeDir; }

ConfigFile.cpp
View Code

此類采用單例模式,可供多線程是使用,同時,添加了個人認為很又必要的一些內容。

轉自:https://www.cnblogs.com/kyzc/p/13964243.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM