当前位置: 首页 > news >正文

Qt中QSettings的键值使用QDataStream进行存储

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 &section, 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博客


文章转载自:

http://TgFTh9eK.mnmrx.cn
http://yrpoWsWK.mnmrx.cn
http://DkHgL1gQ.mnmrx.cn
http://9vlGtmWt.mnmrx.cn
http://wBud8xAq.mnmrx.cn
http://AocxdZ9a.mnmrx.cn
http://7zvfNsaA.mnmrx.cn
http://xkkSDMzU.mnmrx.cn
http://w4GFXKba.mnmrx.cn
http://PuqsKrW0.mnmrx.cn
http://3sBanUZP.mnmrx.cn
http://4ZTiN8uo.mnmrx.cn
http://UvVRf3aB.mnmrx.cn
http://nVUFi1u5.mnmrx.cn
http://wpfOLkyM.mnmrx.cn
http://HVhKHhEQ.mnmrx.cn
http://6V5evHme.mnmrx.cn
http://S3D5QFVO.mnmrx.cn
http://YQFbweW9.mnmrx.cn
http://h286hsO0.mnmrx.cn
http://n8dUpC7x.mnmrx.cn
http://j2lFkapp.mnmrx.cn
http://fZeXsUIe.mnmrx.cn
http://xg7i1aBM.mnmrx.cn
http://e5rptfoO.mnmrx.cn
http://dpTE29YF.mnmrx.cn
http://8t9lSGCR.mnmrx.cn
http://oP65hHxe.mnmrx.cn
http://NIaRMhuX.mnmrx.cn
http://F5Qyv7f0.mnmrx.cn
http://www.dtcms.com/a/362560.html

相关文章:

  • 【Vue2 ✨】Vue2 入门之旅(七):事件处理
  • 从spring MVC角度理解HTTP协议及Request-Response模式
  • 自学嵌入式第三十二天:网络编程-UDP
  • 基于单片机醉酒驾驶检测系统/酒精检测/防疲劳驾驶设计
  • Angular事件处理全攻略:从基础到进阶的完整指南
  • GEO 应用实践研讨会:探索行业新路径,激发企业新活力
  • IoT Power软件 -- 每次开启强制升级解决方法
  • DVWA靶场通关笔记-DOM型XSS(Impossible级别)
  • CentOS7.6
  • 基于Force-closure评估的抓取计算流程
  • gitlab中回退代码,CI / CD 联系运维同事处理
  • RAGFlow——知识库检索系统开发实战指南(包含聊天和Agent模式)
  • 微信小程序备忘
  • ResponseBodyEmitter介绍
  • HarmonyOS 鸿蒙系统自带的 SymbolGlyph 图标组件详解
  • 【学Python自动化】 8.1 Python 与 Rust 错误处理对比学习笔记
  • 拔河(蓝桥杯)(前缀和)
  • Docker CI/CD 自动化部署配置指南
  • 【Datawhale之Happy-LLM】3种常见的decoder-only模型——Github最火大模型原理与实践教程task07
  • C#---共享项目
  • 【C++变量和数据类型:从基础到高级】
  • AI 在教育领域的落地困境:个性化教学与数据隐私的平衡之道
  • 线程特定存储
  • 【Go语言入门教程】 Go语言的起源与技术特点:从诞生到现代编程利器(一)
  • 深入浅出 RabbitMQ-TTL+死信队列+延迟队列
  • idea上传本地项目代码到Gitee仓库教程
  • 【论文阅读】Deepseek-VL:走向现实世界的视觉语言理解
  • 【Web前端】JS+DOM来实现乌龟追兔子小游戏
  • GPT-5在医疗领域应用的研究效能初探(下)
  • 跨平台游戏引擎 Axmol-2.8.0 发布