1. QDataStream介紹
數據流是編碼信息的二進制流,與主機的操作系統、CPU 或字節順序完全無關。例如,Windows 系統下 PC 寫入的數據流可由運行 Solaris 的 Sun SPARC 讀取。
您還可以使用數據流讀/寫raw unencoded binary data?。如果需要 "解析 "輸入流,請參閱QTextStream?。
QDataStream 類實現了 C++ 基本數據類型的序列化,如char
,short
,int
,char *
?等。更復雜數據的序列化是通過將數據分解成原始單元來實現的。
上面內容參考于:QDataStream Class | Qt Core | Qt 6.9.1
2. QSettings介紹
用戶通常希望應用程序能跨會話記住其設置(窗口大小和位置、選項等)。在 Windows 系統中,這些信息通常存儲在系統注冊表中,而在 macOS 和 iOS 中則存儲在屬性列表文件中。在 Unix 系統上,由于缺乏標準,許多應用程序(包括 KDE 應用程序)都使用 INI 文本文件。
QSettings 是對這些技術的抽象,使您能以可移植的方式保存和恢復應用程序設置。它還支持custom storage formats?。
QSettings 的 API 基于QVariant?,允許您以最小的代價保存大多數基于值的類型,如QString?、QRect?和QImage?。
上面內容參考于:QSettings Class | Qt Core | Qt 6.9.1
3.demo
1. 需求:鍵值使用QDataStream轉換成二進制數據存儲到a.ini文件中;同時可以解析a.ini內容到output.ini中。
#include <QCoreApplication>
#include <QSettings>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QByteArray>// 序列化數據并存儲到 a.ini(按 key=value 格式,但值是二進制)
void saveToSettings() {// 1. 準備要序列化的數據QString str = "the answer is";qint32 num = 42;// 2. 分別序列化 str 和 num,并存儲到 a.ini 的對應鍵中QSettings settings("a.ini", QSettings::IniFormat);// 序列化 str 并存儲到 text 鍵QByteArray strData;QDataStream strOut(&strData, QIODevice::WriteOnly);strOut << str;settings.setValue("text", strData);// 序列化 num 并存儲到 number 鍵QByteArray numData;QDataStream numOut(&numData, QIODevice::WriteOnly);numOut << num;settings.setValue("number", numData);qDebug() << "Data serialized and saved to a.ini (Base64 encoded)";
}// 從 a.ini 讀取并反序列化,然后寫入 output.ini
void loadAndWriteToOutputIni() {// 1. 從 a.iniQSettings settings("a.ini", QSettings::IniFormat);// 讀取 text 并反序列化QByteArray strData = (settings.value("text").toByteArray());QDataStream strIn(strData);QString str;strIn >> str;// 讀取 number 并反序列化QByteArray numData = (settings.value("number").toByteArray());QDataStream numIn(numData);qint32 num;numIn >> num;// 2. 將解析后的數據寫入 output.ini(標準鍵值對格式)QSettings outputSettings("output.ini", QSettings::IniFormat);outputSettings.setValue("text", str);outputSettings.setValue("number", num);qDebug() << "Deserialized data written to output.ini";qDebug() << "Output String:" << str;qDebug() << "Output Number:" << num;
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);saveToSettings(); // 序列化并存儲到 a.iniloadAndWriteToOutputIni(); // 從 a.ini 讀取并寫入 output.inireturn a.exec();
}
運行結果如下:
(1)存入文件a.ini
(2)解析文件output.ini
2.需求:寫一個解析a.ini內容所有節、鍵值對的代碼到output.ini中。
#include <QCoreApplication>
#include <QSettings>
#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QByteArray>// 反序列化二進制數據(假設存儲的是 QString 或 qint32)
QVariant deserializeBinaryData(const QByteArray &data) {QDataStream stream(data);QVariant result;// 嘗試反序列化為 QStringQString str;stream >> str;if (!stream.status()) {return str;}// 嘗試反序列化為 qint32stream.device()->seek(0); // 重置流位置qint32 num;stream >> num; //!!!這里數字轉換正確了,但是stream轉換錯誤,可能跟字節序有關,處理方法:設置字節序或者數字直接以原始數字存儲,非二進制存儲。if (stream.status() == QDataStream::Ok) {return num;}// 如果都不是,返回原始 QByteArrayreturn data;
}// 遍歷 a.ini 的所有節和鍵值對,反序列化二進制數據并寫入 output.ini
void processIniFile() {// 檢查 a.ini 是否存在if (!QFile::exists("a.ini")) {qCritical() << "Error: a.ini does not exist!";return;}QSettings inputSettings("a.ini", QSettings::IniFormat);QSettings outputSettings("output.ini", QSettings::IniFormat);QStringList allKeys = inputSettings.allKeys(); // 例如: ("General/number", "General/text")foreach (const QString &fullKey, allKeys) {// 提取節名和鍵名int lastSlash = fullKey.lastIndexOf('/');QString section = fullKey.left(lastSlash);QString key = fullKey.mid(lastSlash + 1);// 讀取原始數據并反序列化QByteArray rawData = inputSettings.value(fullKey).toByteArray();QVariant value = deserializeBinaryData(rawData);// 寫入 output.inioutputSettings.beginGroup(section);outputSettings.setValue(key, value);outputSettings.endGroup();}qDebug() << "Processed a.ini and wrote to output.ini";
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);processIniFile(); // 遍歷 a.ini 并寫入 output.inireturn a.exec();
}
運行結果如下:
上面的內容轉出內容有下面問題:
(1)鍵值對結構錯誤。
????????由于之前使用下面代碼,inputSettings.childGroups返回的內容是空,所以使用的上面上面方法遍歷鍵值。
// 1. 遍歷所有節(Sections)QStringList sections = inputSettings.childGroups();foreach (const QString §ion, sections) {inputSettings.beginGroup(section);outputSettings.beginGroup(section);// 2. 遍歷當前節的所有鍵QStringList keys = inputSettings.childKeys();foreach (const QString &key, keys) {QByteArray rawData = inputSettings.value(key).toByteArray();QVariant value = deserializeBinaryData(rawData);// 3. 寫入 output.ini(保持相同的鍵值對結構)outputSettings.setValue(key, value);}inputSettings.endGroup();outputSettings.endGroup();}
查閱的資料得到的一種解釋是:QSettings?的?childGroups()?行為:
childGroups()?返回的是?當前組(Group)下的子組,而不是當前組本身。
如果你沒有調用?beginGroup()?進入某個組,childGroups()?返回的是?頂層組(即?[]?空組的子組)。
如果?a.ini?只有?[General]?這一層,而沒有嵌套的子組(如?[General/SubSection]),那么?childGroups()?可能會返回空列表。
(2)數字沒有正確解析。
實際測試中stream >> num; ?這里數字轉換正確了,但是stream轉換錯誤,可能跟字節序有關,處理方法:設置字節序或者數字直接以原始數字存儲,而非二進制存儲。
查閱的資料得到的一種解釋是:從理論上看,二進制流可以設計為完全獨立于硬件(如 UTF-8 編碼的文本),但實際場景中(如?QDataStream
?或網絡協議),二進制流的解釋往往依賴隱式或顯式的字節序約定。
CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.5)project(testQDataB LANGUAGES CXX)set(CMAKE_INCLUDE_CURRENT_DIR ON)set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(Qt5Core)add_executable(testQDataBmain.cpp
)
target_link_libraries(testQDataB Qt5::Core)
附加
讀寫ini也可參考:總結:Qt讀寫ini配置文件(QSettings)_qt ini-CSDN博客