Qt服務應用操作

xjx111發表於2024-07-19

0.前置知識

1. ini檔案

INI(初始化檔案)是一種配置檔案格式,廣泛用於儲存配置資料。它通常用於作業系統、應用程式和軟體庫的配置。INI 檔案以文字形式儲存資料,並且具有以下特點:

  1. 簡單性:INI 檔案的結構簡單,易於閱讀和編輯,通常由註釋、節(sections)和鍵值對(key-value pairs)組成。
  2. 節(Sections):INI 檔案由多個節組成,每個節都有一個方括號包圍的標題,例如 [General][Settings]。節用於邏輯上分組相關的配置項。
  3. 鍵值對(Key-Value Pairs):在每個節中,配置資料以鍵值對的形式儲存,鍵和值之間用等號(=)分隔。例如:
    Width=800
    Height=600
    
  4. 註釋:INI 檔案支援註釋,以分號(;)或井號(#)開頭的行被視為註釋,不會被程式解析。
  5. 大小寫敏感性:在某些系統中,INI 檔案的鍵名是大小寫敏感的,這意味著 Widthwidth 被視為兩個不同的鍵。
  6. 多平臺支援:INI 檔案格式在不同的作業系統上都得到廣泛支援,包括 Windows、Linux 和 macOS。
  7. 易於使用:由於其簡單的格式,INI 檔案可以很容易地被文字編輯器或專門的配置管理工具處理。
  8. 可擴充套件性:儘管INI檔案的基本結構相對固定,但開發者可以根據需要新增自定義的節和鍵值對。
  9. 應用場景:INI 檔案常用於儲存使用者偏好設定、程式引數、系統配置等,它們可以在程式啟動時被讀取,以初始化程式的狀態。
  10. 示例:一個典型的 INI 檔案可能如下所示:
    ; 這是註釋
    [General]
    Name=My Application
    Version=1.0
    
    [Settings]
    Width=1024
    Height=768
    Language=English
    

INI 檔案是一種非常基本的配置檔案格式,儘管它在現代應用程式中可能不如 JSON 或 XML 那樣常見,但它仍然因其簡單性和易於使用而在某些場景下被廣泛使用。

2.JSON檔案

JSON(JavaScript Object Notation)是一種輕量級的資料交換格式,易於人閱讀和編寫,同時也易於機器解析和生成。它基於JavaScript的一個子集,但獨立於語言,被廣泛用於資料交換和配置檔案。以下是JSON的一些關鍵特點:

  1. 文字格式:JSON是一種純文字格式,可以由任何文字編輯器生成或讀取。
  2. 資料型別:JSON支援以下資料型別:
    • 字串(String)
    • 數字(Number)
    • 物件(Object),無序的鍵值對集合
    • 陣列(Array),有序的值集合
    • 布林值(Boolean)
    • 空值(Null)
  3. 鍵值對:JSON物件由鍵值對組成,鍵是字串,值可以是字串、數字、物件、陣列、布林值或空值。
  4. 陣列:JSON陣列是有序的值集合,可以包含不同型別的值。
  5. 可擴充套件性:JSON結構可以非常靈活,支援巢狀物件和陣列。
  6. 自描述性:JSON資料格式本身不包含資料型別資訊,但透過結構可以推斷資料型別。
  7. 語言無關性:雖然JSON起源於JavaScript,但它與程式語言無關,可以被多種程式語言解析和生成。
  8. 易於解析:許多程式語言都提供瞭解析JSON的工具和庫,使得處理JSON資料變得簡單。
  9. 廣泛使用:JSON在Web開發中非常流行,常用於客戶端和伺服器之間的資料交換,也被用於配置檔案、日誌檔案等。
  10. 示例
    {
      "name": "John Doe",
      "age": 30,
      "is_student": false,
      "grades": [88, 92, 77],
      "address": {
        "street": "123 Main St",
        "city": "Anytown",
        "zip": "12345"
      }
    }
    
  11. 安全性:由於JSON格式的簡單性,它不容易受到注入攻擊,但處理JSON資料時仍需注意安全性,避免執行不安全的解析操作。
  12. 應用場景:JSON常用於以下場景:
    • Web API響應和請求
    • 配置檔案
    • 資料儲存和傳輸
    • 日誌記錄
    • 應用程式的本地儲存
      由於其簡單性和靈活性,JSON已經成為資料交換和配置管理中的首選格式之一。

不同類間關係

QJsonDocumentQJsonObjectQJsonValue 是 Qt 框架中處理 JSON 資料的三個核心類,它們之間的關係如下:

  1. QJsonDocument
    • QJsonDocument 是一個類,用於表示 JSON 文件。它可以包含一個 JSON 物件(QJsonObject)或一個 JSON 陣列(QJsonArray)。
    • 它提供了從字串或資料建立 JSON 文件的功能,以及將 JSON 文件轉換為字串或資料的功能。
    • QJsonDocument 可以被視為 JSON 資料的容器。
  2. QJsonObject
    • QJsonObject 是一個類,表示 JSON 物件,即一組鍵值對,其中鍵是字串,值可以是字串、數字、布林值、null、另一個 JSON 物件或 JSON 陣列。
    • 它提供了新增、查詢和刪除鍵值對的方法。
    • QJsonObjectQJsonDocument 可以包含的資料型別之一。
  3. QJsonValue
    • QJsonValue 是一個類,表示 JSON 值,它可以是以下型別之一:字串、數字、布林值、null、QJsonObjectQJsonArray
    • 它是一個變體型別,可以儲存 JSON 資料的任何基本型別,以及 JSON 物件和陣列。
    • QJsonValue 用於訪問和操作 QJsonObject 中的值。
      這三個類之間的關係可以這樣理解:QJsonDocument 是整個 JSON 資料的頂層容器,它可以包含一個 QJsonObjectQJsonArrayQJsonObject 是實際儲存鍵值對的地方,而 QJsonValueQJsonObject 中鍵對應的值的型別。
      例如,如果你有一個 JSON 物件如下:
{
  "name": "John Doe",
  "age": 30,
  "is_student": false,
  "grades": [88, 92, 77]
}

在這個例子中:

  • QJsonDocument 將包含整個 JSON 物件。
  • QJsonObject 將包含鍵 "name", "age", "is_student", 和 "grades",以及它們對應的值。
  • QJsonValue 將分別表示每個鍵對應的值,例如 "John Doe"(字串)、30(數字)、false(布林值)和 [88, 92, 77](陣列)。
    使用 Qt 的 JSON API,你可以輕鬆地解析 JSON 字串,建立和修改 JSON 物件,以及序列化 JSON 物件回字串。

3.XML檔案

XML(可擴充套件標記語言,eXtensible Markup Language)是一種標記語言,主要用於儲存和傳輸資料。它被設計為簡單、易於理解和使用,同時具有自我描述性,這意味著資料的結構在資料本身中定義。以下是XML的一些關鍵特點:

  1. 自我描述性:XML文件中的元素和屬性定義了資料的結構和含義,無需外部的DTD(文件型別定義)或XML Schema。
  2. 可擴充套件性:使用者可以定義自己的元素和屬性,使其適應不同的應用需求。
  3. 平臺無關性:XML是一種純文字格式,可以在任何作業系統和平臺上使用。
  4. 資料和檢視分離:XML專注於資料的儲存和傳輸,而顯示和處理資料則由其他技術(如CSS、XSLT等)處理。
  5. 支援名稱空間:XML支援名稱空間,允許不同來源的元素和屬性在同一文件中共存而不發生衝突。
  6. 支援屬性:XML元素可以包含屬性,屬性提供了關於元素的額外資訊。
  7. 支援註釋:XML支援註釋,註釋在文件中被忽略,但可以用於提供額外的資訊或解釋。
  8. 支援巢狀:XML元素可以巢狀在其他元素中,形成層次結構。
  9. 資料型別:XML Schema定義了資料型別,可以對元素和屬性的值進行型別約束。
  10. 廣泛使用:XML在許多領域中得到應用,如配置檔案、資料交換、文件管理等。
  11. 示例
    <?xml version="1.0" encoding="UTF-8"?>
    <bookstore>
      <book>
        <title lang="en">Harry Potter</title>
        <author>J.K. Rowling</author>
        <year>1997</year>
        <price>29.99</price>
      </book>
      <book>
        <title lang="en">The Hobbit</title>
        <author>J.R.R. Tolkien</author>
        <year>1937</year>
        <price>19.99</price>
      </book>
    </bookstore>
    
  12. 解析和生成:許多程式語言提供瞭解析和生成XML的庫,使得處理XML資料變得簡單。
  13. 安全性:XML本身是安全的,但需要小心處理,避免XML注入攻擊。
  14. 相關技術
    • XSLT(可擴充套件樣式表語言轉換):用於將XML文件轉換為其他格式,如HTML、文字或另一個XML文件。
    • XPath:用於在XML文件中進行選擇和導航。
    • XQuery:用於查詢XML資料。
      XML是一種非常靈活和強大的資料交換格式,儘管在某些場景下可能被更輕量級的格式(如JSON)所取代,但它在許多領域中仍然非常重要和有用。

不同類之間的關係

在Qt框架中,處理XML文件涉及幾個關鍵類,這些類共同構成了Qt的XML DOM(文件物件模型)API。以下是QDomDocumentQDomProcessingInstructionQDomElementQDomText這幾個類的關係及其作用:

  1. QDomDocument

    • QDomDocument 類代表整個XML文件。它是所有其他DOM物件的容器。
    • 你可以使用 QDomDocument 來建立新的XML文件或載入現有的XML文件。
    • QDomDocument 提供了訪問和修改文件中元素的方法,如 createElement()createTextNode()createElementNS() 等。
  2. QDomElement

    • QDomElement 類代表XML文件中的一個元素。元素是XML文件的基本構建塊,可以包含文字、屬性和其他元素。
    • 你可以使用 QDomElement 來訪問元素的標籤名、屬性、子元素等。
    • QDomElement 也可以用來建立新的元素或修改現有元素。
  3. QDomText

    • QDomText 類代表XML元素中的文字節點。它用於儲存元素的文字內容。
    • 每個 QDomText 物件都是 QDomNode 的子類,可以被新增到 QDomDocumentQDomElement 中。
  4. QDomProcessingInstruction

    • QDomProcessingInstruction 類代表XML文件中的處理指令(Processing Instruction)。處理指令通常用於提供關於文件的額外資訊,例如指定樣式表或轉換指令。
    • 處理指令有一個目標(target)和一個資料(data),分別用於指定處理指令的型別和提供相關的資料。

關係和層次結構

  • QDomDocument 是最頂層的容器,包含整個XML文件。
  • QDomElement 是文件中的元素,可以包含 QDomText 節點和其他 QDomElement 節點(即子元素)。
  • QDomText 是元素的子節點,儲存文字內容。
  • QDomProcessingInstruction 是文件的一部分,通常位於文件的頂部,提供關於文件的處理指令。

示例

假設有一個簡單的XML文件:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<bookstore>
  <book>
    <title>Harry Potter</title>
    <author>J.K. Rowling</author>
    <year>1997</year>
  </book>
</bookstore>

在這個文件中:

  • QDomDocument 包含整個文件。
  • <bookstore> 是一個 QDomElement,它是文件的根元素。
  • <book>QDomElement 的子元素。
  • <title><author><year> 都是 QDomElement,包含書籍的標題、作者和出版年份。
  • Harry PotterJ.K. Rowling1997QDomText 節點,分別儲存在相應的 QDomElement 中。
  • <?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="style.xsl"?>QDomProcessingInstruction,提供文件的版本資訊和樣式錶連結。

透過這些類,Qt的XML DOM API提供了一種強大的方式來解析、建立和操作XML文件。

4. 不同的編碼方法

在Qt中,處理字串編碼是一個常見的任務,尤其是當你需要在應用程式中處理不同語言或與不同系統互動時。Qt提供了幾種方法來轉換和處理字串編碼。以下是一些主要的編碼轉換方法及其用途:

  1. QString::toUtf8()
    • QString 物件轉換為UTF-8編碼的 QByteArray
    • UTF-8是最常用的Unicode編碼方式,廣泛用於網路傳輸和跨平臺相容性。
    • 用法示例:
      QByteArray utf8Data = myQString.toUtf8();
      
  2. QString::toLocal8Bit()
    • QString 物件轉換為本地8位編碼的 QByteArray
    • 本地編碼通常是系統的預設編碼(如Windows上的CP1252或Linux上的ISO-8859-1)。
    • 適用於將字串傳送到系統API或使用本地編碼的檔案。
    • 用法示例:
      QByteArray localData = myQString.toLocal8Bit();
      
  3. QString::fromLatin1()
    • QString 物件轉換為Latin-1(ISO-8859-1)編碼的 QByteArray
    • 主要用於西歐語言,不包含擴充套件字元。
    • 用法示例:
      QByteArray latin1Data = myQString.fromLatin1();
      
  4. QString::fromUtf8()
    • 將UTF-8編碼的 QByteArray 或 C 風格字串轉換為 QString
    • 用於從外部源(如檔案或網路)讀取UTF-8編碼的資料並轉換為Qt內部的Unicode字串。
    • 用法示例:
      QString unicodeString = QString::fromUtf8(someUtf8Data);
      
  5. QString::fromLocal8Bit()
    • 將本地8位編碼的 QByteArray 轉換為 QString
    • 用於從系統API或本地編碼檔案讀取字串,並轉換為Unicode字串。
    • 用法示例:
      QString unicodeString = QString::fromLocal8Bit(someLocalData);
      
  6. QTextCodec
    • QTextCodec 類提供了編碼和解碼的功能,支援各種編碼。
    • 可以用於自定義編碼的轉換,或者作為更通用的解決方案。
    • 用法示例:
      QTextCodec *codec = QTextCodec::codecForName("GB18030");
      QByteArray encodedData = codec->fromUnicode(myQString);
      

為什麼使用這些轉換方法?

  • 跨平臺相容性:不同的作業系統可能有不同的預設編碼,使用這些方法可以確保應用程式在不同平臺上都能正確處理字串。
  • 網路傳輸:網路通常使用UTF-8編碼,因此將字串轉換為UTF-8格式是必要的。
  • 系統API:許多系統API要求使用特定的編碼格式,例如Windows的API可能要求使用本地編碼。
  • 國際化和本地化:應用程式可能會支援多種語言,正確處理不同語言的編碼是提供良好使用者體驗的關鍵。
    理解並正確使用這些編碼轉換方法對於開發能夠在全球範圍內執行的應用程式至關重要。

1.INI檔案讀寫

void WriteIniFiles()
{
    // 直接使用QSettings類讀寫INI檔案
    QSettings *configWritenIniFiles = new QSettings("MySQLFiles.ini", QSettings::IniFormat);

    // 向ini檔案中寫入資料資訊
    configWritenIniFiles->setValue("/database/ip", "192.168.12.189");
    configWritenIniFiles->setValue("/database/port", "6666");
    configWritenIniFiles->setValue("/database/user", "root");
    configWritenIniFiles->setValue("/database/password", "123456");

    configWritenIniFiles->setValue("/notice/version", "6.12");
    configWritenIniFiles->setValue("/notice/time", "17點22分");


    // 寫入後刪除指標
    delete configWritenIniFiles;
}
void ReadIniFiles()
{
    QSettings *configWritenIniFiles = new QSettings("MySQLFiles.ini", QSettings::IniFormat);

    QString strip = configWritenIniFiles->value("/database/ip").toString();

    qDebug() << strip.toUtf8().data();

    delete configWritenIniFiles;
}

2.Json檔案讀寫

點選檢視程式碼
void write()
{
    // 1、建立Json物件
    QJsonObject mySQLinfo;

    mySQLinfo.insert("ip", "192.168.1.1");
    mySQLinfo.insert("port", 6666);
    mySQLinfo.insert("user", "1");
    mySQLinfo.insert("password", "123");

    QJsonObject jsoninfo;
    jsoninfo.insert("code", 1);
    jsoninfo.insert("dbmsg", "MySQL資料庫配置引數");
    jsoninfo.insert("data", mySQLinfo);

    // 2、建立Json文件
    QJsonDocument jsondoc;
    jsondoc.setObject(jsoninfo);

    // 3、建立檔案
    QFile qfiles("./databaseJsonfiles.json");
    if(qfiles.open(QIODevice::WriteOnly))
    {
        qfiles.write(jsondoc.toJson());
        qfiles.close();
        qDebug() << "Json資料檔案寫入成功";
    }

    QMessageBox::information(this, "提示", "Json資料檔案寫入成功");
}


void read()
{
    QString strJson;

    // QFile 讀取出來為QString格式
    QFile qfiles("./databaseJsonfiles.json");
    if( qfiles.open(QIODevice::ReadOnly))
    {
        strJson = qfiles.readAll();
        qfiles.close();
    }

    // 將QString格式轉換為Json格式
    QJsonParseError jsonError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(strJson.toUtf8(), &jsonError);

    QString strTemp;
    if(!jsonDoc.isEmpty() && (jsonError.error == QJsonParseError::NoError))
    {
        // 只要Jsondoc不為空,和Jsonerror沒有錯誤
        // 將他轉換Json物件

        QJsonObject json = jsonDoc.object();
        QJsonValue code = json.value("code");
        QJsonValue data = json.value("data");

        // 檢查資料
        if(code.isUndefined() || code.toDouble()!=1 || data.isUndefined() || !data.isObject())
        {
            QMessageBox::critical(this, "錯誤", "轉換JSon資料錯誤,請重新檢查");
            exit(100);
        }

        // 如果沒有錯誤
        QJsonObject databaseinfo = data.toObject();

        QJsonValue dbip = databaseinfo.value("ip");
        QJsonValue dbport = databaseinfo.value("port");
        QJsonValue dbuser = databaseinfo.value("user");
        QJsonValue dbpassword = databaseinfo.value("password");

        // 檢查介面是否正確

        if(dbip.isUndefined()
            || dbport.isUndefined()
            || dbuser.isUndefined()
            || dbpassword.isUndefined())
        {
            qDebug() << "介面錯誤";
            QMessageBox::critical(this, "錯誤", "介面錯誤");
            exit(100);
        }

        QString strip = dbip.toString();
        int port = dbport.toInt();
        QString struser = dbuser.toString();
        QString strPassword = dbpassword.toString();

        // 判斷是否為空
        if(strip.isEmpty() || struser.isEmpty() ||strPassword.isEmpty())
        {
            qDebug() << "不能為空";
            QMessageBox::critical(this, "錯誤", "不能為空");
            exit(100);
        }

        QMessageBox::information(this, "提示",
                                 "QJson格式Json資料檔案讀取成功\n"
                                 "dbIP:" + strip + "\n"
                                 "dbPort:" + QString::number(port) + "\n"
                                 "dbUser:" + struser + "\n"
                                 "dbPassword:" + strPassword);
    }

    QMessageBox::information(this, "提示", "QString格式Json資料檔案讀取成功\n"+strJson);
}


3.XML檔案讀寫

  1. GB2312 和 UTF-8 編碼存在問題,未解決!!!
  2. 存在中文時可以寫入,但是無法讀出
點選檢視程式碼
void MainWindow::on_pushButton_write_clicked()
{
    if (!openxmlfiles())
    {
        QMessageBox::critical(this, "警告", "開啟檔案失敗");
        return;
    }

    QDomDocument domdoct; // 頂層容器,包含整個XML文件
    QDomProcessingInstruction version;
    version = domdoct.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    domdoct.appendChild(version);

    QDomElement domrootelement = domdoct.createElement("factory"); // 建立頂層節點
    domdoct.appendChild(domrootelement);

    QDomElement itemrootelement = domdoct.createElement("worker"); // 建立父節點
    {
        QDomElement node1 = domdoct.createElement("ID");
        QDomText domtext1 = domdoct.createTextNode("ID");
        domtext1.setData(ui->lineEdit_id->text());
        node1.appendChild(domtext1);
        itemrootelement.appendChild(node1);

        QDomElement node2 = domdoct.createElement("Name");
        QDomText domtext2 = domdoct.createTextNode("Name");
        domtext2.setData(ui->lineEdit_name->text());
        node2.appendChild(domtext2);
        itemrootelement.appendChild(node2);

        QDomElement node3 = domdoct.createElement("Sex");
        QDomText domtext3 = domdoct.createTextNode("Sex");
        domtext3.setData(ui->lineEdit_sex->text());
        node3.appendChild(domtext3);
        itemrootelement.appendChild(node3);

        QDomElement node4 = domdoct.createElement("Edu");
        QDomText domtext4 = domdoct.createTextNode("Edu");
        domtext4.setData(ui->lineEdit_edu->text());
        node4.appendChild(domtext4);
        itemrootelement.appendChild(node4);

        QDomElement node5 = domdoct.createElement("Dep");
        QDomText domtext5 = domdoct.createTextNode("Dep");
        domtext5.setData(ui->lineEdit_dep->text());
        node5.appendChild(domtext5);
        itemrootelement.appendChild(node5);

        QDomElement node6 = domdoct.createElement("Slary");
        QDomText domtext6 = domdoct.createTextNode("Slary");
        domtext6.setData(ui->lineEdit_slary->text());
        node6.appendChild(domtext6);
        itemrootelement.appendChild(node6);
    }
    domrootelement.appendChild(itemrootelement);

    m_qfiles.write(domdoct.toString().toLocal8Bit().data());
    m_qfiles.close();

    QMessageBox::information(this, "提示", "寫入檔案成功");


}

void MainWindow::on_pushButton_read_clicked()
{
    if (!openxmlfiles())
    {
        QMessageBox::critical(this, "警告", "開啟檔案錯誤");
        return;
    }

    // QByteArray data = m_qfiles.readAll();

    QDomDocument domdoct;

    if (!domdoct.setContent(&m_qfiles))
    {
        m_qfiles.close();
        QMessageBox::critical(this, "警告", "setContent錯誤");
        return;
    }

    QDomElement root = domdoct.documentElement(); // 讀取根節點, 類似於連結串列,需要從根節點開始讀取

    QDomNode node = root.firstChild(); // 第一個子節點,也是一個包含許多節點的父節點

    while(!node.isNull())
    {
        QDomNodeList sonlist = node.childNodes(); // 第一個子節點中的所有節點資訊
        QString rootname = node.toElement().tagName(); // 讀取父節點的標籤名

        if (rootname.compare("worker") == 0)
        {
            // 將子節點集合資訊讀取出來
            readrootxml(sonlist);
        }
        node = node.nextSibling(); //讀取下一個父節點
    }



}

bool MainWindow::openxmlfiles()
{
    m_qfiles.setFileName(strCurrentFilePath + strCurrentFileName);// 如果沒有,則建立檔案
    return m_qfiles.open(QIODevice::ReadWrite | QFile::Text);
}

void MainWindow::readrootxml(QDomNodeList sonnodelist)
{
    for (int sonnode = 0; sonnode < sonnodelist.size(); sonnode++)
    {
        // 獲取子節點
        QDomElement sonelement = sonnodelist.at(sonnode).toElement();

        if(sonelement.toElement().tagName().compare("ID") == 0) // 取出子節點進行比較
        {
            ui->lineEdit_id2->setText(sonelement.text());
        }
        else if(sonelement.toElement().tagName().compare("Name") == 0)
        {
            ui->lineEdit_name2->setText(sonelement.text());
        }else if(sonelement.toElement().tagName().compare("Sex") == 0)
        {
            ui->lineEdit_sex2->setText(sonelement.text());
        }else if(sonelement.toElement().tagName().compare("Edu") == 0)
        {
            ui->lineEdit_edu2->setText(sonelement.text());
        }else if(sonelement.toElement().tagName().compare("Dep") == 0)
        {
            ui->lineEdit_dep2->setText(sonelement.text());
        }else if(sonelement.toElement().tagName().compare("Slary") == 0)
        {
            ui->lineEdit_slary2->setText(sonelement.text());
        }
    }
}

相關文章