Qt基礎之配置文件


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

1.INI文件

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

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

  Qt寫文件示例如下:

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

 2.XML文件

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

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

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

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

  c.清理內存

  具體示例代碼:

  1 //xml類型配置文件讀寫
  2 bool ConfigFile::LoadXMLFile(QString file_path)
  3 {
  4     bool bRet = true;
  5     //step1:讀文件
  6     QFile file(file_path);
  7     if (!file.open(QFile::ReadOnly))
  8     {
  9         errMsg = QString("文件打開失敗,%1").arg(file.errorString());
 10         return false;
 11     }
 12  
 13     QString errorStr;
 14     int errorLine;
 15     int errorColumn;
 16  
 17     //qml數據存儲格式
 18     QDomDocument doc;
 19     //step2:轉換成xml數據格式
 20     if (!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
 21     {
 22         errMsg = QString("QML解析錯誤,%1,%2,%3").arg(errorStr)
 23              .arg(QString::number(errorLine)).arg(QString::number(errorColumn));
 24          file.close();
 25          return false;
 26     }
 27     //此時已經不需要文件句柄,可關閉
 28     file.close();
 29  
 30     //根節點元素    
 31     QDomElement root = doc.documentElement();
 32  
 33  #pragma region "每個文件不一樣,由此處開始修改"
 34      //簡單節點結構
 35      QDomElement parts = root.firstChildElement("module");
 36      if (parts.isNull())
 37      {
 38          bRet = false;
 39          errMsg = "文件格式異常,未發現[module]節點";
 40          goto _RET;
 41       }
 42      else
 43      {
 44          //ups
 45          QDomElement temp = parts.firstChildElement("ups");
 46          if (temp.isNull())
 47           {
 48               bRet = false;
 49               errMsg = "文件格式異常,未發現[model/ups]節點";
 50               goto _RET;
 51           }
 52           else
 53           {
 54               QString st = temp.text();
 55               if (st.compare("true") == 0)
 56                   modeUPS = true;
 57               else
 58                   modeUPS = false;
 59           }
 60              
 61         
 62       //多重嵌套、重復結構
 63       {
 64          parts = root.firstChildElement("processor_monitor");
 65          if (parts.isNull())
 66          {
 67              bRet = false;
 68              errMsg = QString("文件格式異常,未發現[processor_monitor]節點");
 69              goto _RET;
 70          }
 71          else
 72          {
 73                //循環解析,獲取測量點數據
 74               QDomElement subElement = parts.firstChildElement();
 75               while (!subElement.isNull())
 76               {
 77                   if (subElement.tagName().compare("processor") == 0)
 78                   {
 79                      ProcessorInfo tempValue;
 80                       if (!GetProcessorInfo(subElement, tempValue))
 81                       {
 82                           bRet = false;
 83                           errMsg = QString("進程監控節點解析失敗,%1").arg(errMsg);
 84                           goto _RET;
 85                       }
 86                       else
 87                           vecProcessorInfo.push_back(tempValue);
 88                   }
 89   
 90                   subElement = subElement.nextSiblingElement();
 91               }           
 92           }
 93       }
 94   
 95  #pragma endregion
 96   
 97   _RET:
 98       doc.clear();
 99       return bRet;
100 }
View Code

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

  a.創建DOM結構樹根節點

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

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

  d.將字符串寫入文件

  具體示例代碼:

  1 bool ConfigFile::SaveXMLFile()
  2 {
  3     bool bRet = true;
  4     QFile file(filePath);
  5     QDomDocument doc;           //xml結構
  6 
  7     //以只寫入方式打開,並且打開時清空原來內容
  8     if (!file.open(QFile::WriteOnly | QFile::Truncate))
  9     {
 10         errMsg = QString("文件打開失敗,%1").arg(file.errorString());
 11         return false;
 12     }
 13    
 14     //寫入xml頭部
 15     QDomProcessingInstruction instruction; //添加處理命令
 16     instruction = doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
 17     doc.appendChild(instruction);
 18 
 19     //添加根節點
 20     QDomElement root = doc.createElement("root");
 21     doc.appendChild(root);
 22 
 23 #pragma region  跟隨配置文件記錄項改變
 24     QString strTemp = "";
 25     QDomText text;
 26 
 27     //寫入model節點
 28     {
 29         //ups
 30         QDomElement model = doc.createElement("module");
 31         QDomElement subNode = doc.createElement("ups");
 32         if (modeUPS)
 33             strTemp = "true";
 34         else
 35             strTemp = "false";
 36         text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
 37         subNode.appendChild(text);
 38         model.appendChild(subNode);
 39 
 40         //process
 41         subNode = doc.createElement("process");
 42         if (modeUPS)
 43             strTemp = "true";
 44         else
 45             strTemp = "false";
 46         text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
 47         subNode.appendChild(text);
 48         model.appendChild(subNode);
 49         root.appendChild(model);
 50     }
 51 
 52    
 53     //寫入Processor_monitor節點數據
 54     {
 55         QDomElement eProcessorList = doc.createElement("processor_monitor");
 56       
 57         for (auto it : vecProcessorInfo)
 58         {
 59             QDomElement eProcessor = doc.createElement("processor");
 60 
 61             //name
 62             QDomElement eSub = doc.createElement("name");
 63             text = doc.createTextNode(it.processorName);        //設置括號標簽中間的值
 64             eSub.appendChild(text);
 65             eProcessor.appendChild(eSub);
 66 
 67             //path
 68             eSub = doc.createElement("path");
 69             text = doc.createTextNode(it.processroPath);        //設置括號標簽中間的值
 70             eSub.appendChild(text);
 71             eProcessor.appendChild(eSub);
 72 
 73             //autoStart
 74             if (it.isRestart)
 75                 strTemp = "true";
 76             else
 77                 strTemp = "false";
 78             eSub = doc.createElement("autostart");           
 79             text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
 80             eSub.appendChild(text);
 81             eProcessor.appendChild(eSub);
 82 
 83             //property
 84             strTemp = QString::number(it.stopProprity);
 85             eSub = doc.createElement("proprity");
 86             text = doc.createTextNode(strTemp);        //設置括號標簽中間的值
 87             eSub.appendChild(text);
 88             eProcessor.appendChild(eSub);
 89 
 90             eProcessorList.appendChild(eProcessor);
 91         }
 92 
 93         root.appendChild(eProcessorList);
 94     }
 95 
 96 #pragma endregion
 97 
 98     //輸出到文件
 99     QTextStream out_stream(&file);
100     doc.save(out_stream, 4); //縮進4格
101     file.close();
102     doc.clear()
103     return true;
104 }
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結構:

1 QJsonObject json;
2 json.insert("CMD", QString("GRM"));
3 json.insert("RM", macro_addr);
4 
5 QJsonDocument document;
6 document.setObject(json);
7 QstrJson = document.toJson(QJsonDocument::Compact);
8 if (G_INIFILE->printDbgLog)
9     LOG(INFO) << "發包數據:" << QstrJson.toStdString();
View Code

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

 1 //解析數據
 2     QJsonParseError parseJsonErr;
 3     QJsonDocument document = QJsonDocument::fromJson(qstrRecv.toUtf8(), &parseJsonErr);
 4     if (!(parseJsonErr.error == QJsonParseError::NoError))
 5     {        
 6         errMsg = QString("解析json文件錯誤,%1").arg(parseJsonErr.errorString());
 7         return false;
 8     }
 9 
10     QJsonObject jsonObject = document.object();
11 
12     //CMD
13     QString temp = jsonObject["CMD"].toString();
14     if (temp.compare("GRM") != 0)
15     {
16         errMsg = "收包命令錯誤";
17         return false;
18     }
19 
20     //RM
21     int addrIn = jsonObject["RM"].toInt();
22     if (addrIn != macro_addr)
23     {
24         errMsg = "收包Macro地址錯誤";
25         return false;
26     }
27 
28     //RET
29     if (jsonObject.contains("RET"))
30     {
31         QJsonValue jsonValueList = jsonObject.value("RET");
32         QJsonObject item = jsonValueList.toObject();
33 
34         //ERR
35         int errCode = item["ERR"].toInt();
36         if (errCode != 0)
37         {
38             //MSG
39             QString err = item["MSG"].toString();
40             errMsg = QString("CNC反饋錯誤,錯誤碼:%1,詳情:%2").arg(errCode).arg(err);
41             return false;
42         }
43     }
44 
45     //DATA
46     if (jsonObject.contains("DATA"))
47     {
48         QJsonValue jsonValueList = jsonObject.value("DATA");
49         QJsonObject item = jsonValueList.toObject();
50         macro_value = item["RMV"].toDouble();
51     }
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
#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

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

 


免責聲明!

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



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