Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

本页目录

Qt 数据、I/O 与序列化兼容 ​

1. 数据类型选择 ​

  • UI/Qt API 文本:QString;
  • 协议/文件原始字节:QByteArray;
  • 长期 UTF-8 边界:显式 toUtf8/fromUtf8;
  • 大型数值数组:连续标准/领域容器,避免每个值包装 QVariant;
  • QVariant:封闭属性系统和元对象交互,不是任意序列化格式。

2. QSaveFile ​

重要文档保存优先 QSaveFile:写临时文件,成功 commit() 原子替换目标(具体保证受文件系统影响)。

cpp
QSaveFile file(path);
if (!file.open(QIODevice::WriteOnly)) return error(file.errorString());
if (file.write(bytes) != bytes.size()) return error(file.errorString());
if (!file.commit()) return error(file.errorString());
1
2
3
4

仍需处理磁盘满、权限、目录持久化和旧文件恢复;不要忽略 write/commit 返回值。

3. QDataStream 版本 ​

cpp
QDataStream stream(&device);
stream.setVersion(QDataStream::Qt_6_5);
stream.setByteOrder(QDataStream::LittleEndian);
stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
1
2
3
4

固定 stream 版本稳定 Qt 内建类型的某套编码规则,不会自动为自定义文档提供 schema 演进。文件头还应包含 magic、应用格式版本、feature flags、长度/校验和。

读取不可信长度前设置上限和剩余字节检查,操作后检查 stream.status();不要先按攻击者长度分配数 GB。

4. 长期格式 ​

长期/跨语言数据可评估 JSON/CBOR、Protocol Buffers、HDF5、VTK 等;选择取决于 schema、随机访问、精度、压缩和生态。即使使用成熟格式,领域层仍需版本迁移和未知字段策略。

二进制浮点、字节序、整数宽度明确固定;不要直接 dump C++ struct(padding/ABI)。

5. QSettings ​

QSettings 后端和存储位置跨平台不同,适合用户偏好,不适合大型工程文档或安全 secret。key 要命名空间化并提供默认值/迁移。同步/写入失败需检查 status。

多个进程同时写同一配置的合并语义有限;复杂共享配置使用明确事务存储。

6. QProcess ​

text
start -> wait for started/event -> read stdout/stderr incrementally
      -> finished(exitCode, status) / errorOccurred
1
2

使用 program + argument list,不拼 shell 命令;设置工作目录和环境白名单;分别排空 stdout/stderr 防子进程因 pipe 满阻塞。限制输出大小并解析增量行/帧。

关闭:先请求求解器协议取消/terminate,deadline 后 kill,随后 wait 并收集退出状态。terminate() 的平台语义不同。

7. 文本解析 ​

QTextStream 编码和 locale 要显式;科学数值格式常要求 C locale 和稳定精度。正则适合局部字段,不适合复杂嵌套语法。解析报告包含行/列、上下文和可恢复/致命分类。

8. 面试速答 ​

固定 QDataStream version 是否得到永久兼容? 不会,只固定 Qt 类型规则,自定义 schema 仍要版本化。

QSaveFile 是否等于数据库事务? 不等于,它主要改善单文件替换;跨多文件/外部副作用需更高层事务。

QProcess 为什么要同时读取 stderr? 子进程 pipe 有界,不读可能阻塞子进程,且错误诊断会丢失。

9. 自测答案 ​

直接序列化 QVector<MyClass> 前要确认什么?MyClass 的 stream operator、格式版本、长度上限、字节序和兼容策略。QSettings 能否存密码?不应默认视为安全 secret store。

文件格式需要双层版本 ​

text
container/stream encoding version (Qt serialization behavior)
application schema version (business fields and meaning)
1
2

文件头至少包含 magic、schema version、feature flags、字节序/stream version 和长度;读取先验证上限,再分配。

text
[magic][schema][flags][section count]
  -> each section [type][length][checksum?][payload]
1
2

QDataStream 的边界 ​

双方设置相同 QDataStream::Version 和 byte order;状态错误后停止继续读,不能让后续字段建立在错位 offset 上。Qt 类型编码不自动提供恶意输入安全,字符串/容器计数仍要受文件总预算约束。

JSON 与二进制选择 ​

JSON 可读、跨语言、字段演化方便,但数值精度、大小和解析成本需注意;二进制紧凑快速,却必须严谨版本化。大数组/网格可用分块二进制,元数据用 JSON/CBOR,形成混合 container。

原子保存 ​

text
write temporary in same filesystem
 -> flush/validate
 -> atomically replace target where platform supports
 -> fsync file/directory if durability required
1
2
3
4

QSaveFile 封装常见临时写+commit,但持久性和权限/元数据行为仍需按平台验证。保存失败不能清除 document dirty flag。

增量与分块读取 ​

大 CAE 文件不应一次分配全部:

text
read header/index -> validate offsets
 -> demand-load mesh/result chunks
 -> cache with memory budget
 -> cancel on document close
1
2
3
4

所有 offset+length 运算防溢出,区段不得重叠/越界;压缩数据还限制解压后大小和 CPU 时间。

文本编码 ​

网络/文件统一明确 UTF-8;读取用 QString::fromUtf8 并决定非法序列策略。不要用 local8Bit 作为永久格式。路径是平台对象,显示文本与原始文件系统编码也不要随意互转丢失。

Schema 演化 ​

text
reader supports vN-k ... vN
old fields -> defaults/migration
unknown optional sections -> skip by length
unknown required feature -> reject clearly
1
2
3
4

迁移应转换到当前内存模型,保存时通常写当前版本;保留测试 corpus 覆盖历史文件和损坏输入。

异步 I/O 生命周期 ​

后台读取结果回到 GUI 前,document 可能已关闭/切换。任务携带 document ID/generation,完成时核对仍为当前对象;取消后仍可能收到在途 completion,不能仅断开 signal。

连续追问与自测 ​

问:QDataStream version 是否等于文件版本? 答:不是,它控制 Qt 编码;业务字段语义需独立 schema。

问:为什么临时文件要同文件系统? 答:跨文件系统 rename 通常不具备同样原子替换语义。

  1. 读取 length 后第一步? 答:检查上限、剩余文件范围和整数溢出。
  2. 保存失败 dirty flag 怎么办? 答:保持脏状态并向用户报告。
  3. 异步结果如何防止写入新文档? 答:携带稳定 document identity/generation 并在提交时验证。

工程深化:把本篇知识落到项目里 ​

这一节不是为了凑篇幅,而是把《Qt 数据、I/O 与序列化兼容》从“知道概念”推进到“能在项目里稳定使用”。 阅读时可以把每个知识点都追问成四件事:它保护什么边界,失败时有什么现象,怎样最小复现,怎样写进团队流程。

text
concept -> boundary -> failure signal -> minimal proof -> project rule
1

工程切片 1:最小可复现样例 ​

**场景。**围绕 QDataStream 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。

**边界。**先判断这里讨论的是 QDataStream、schema version 还是 QSaveFile 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QDataStream -> schema version -> QSaveFile -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 2:接口边界 ​

**场景。**围绕 schema version 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。

**边界。**先判断这里讨论的是 schema version、QSaveFile 还是 QProcess 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> schema version -> QSaveFile -> QProcess -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 3:失败注入 ​

**场景。**围绕 QSaveFile 建一个很小的案例,不要一开始就放进完整业务系统。故意制造一个常见错误,让日志、断言或测试先失败,再用修复后的证据说明规则生效。

**边界。**先判断这里讨论的是 QSaveFile、QProcess 还是 编码 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QSaveFile -> QProcess -> 编码 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 4:跨平台差异 ​

**场景。**围绕 QProcess 建一个很小的案例,不要一开始就放进完整业务系统。至少比较 Windows、Linux 或不同编译器下的一个差异,记录差异属于标准、实现还是平台约定。

**边界。**先判断这里讨论的是 QProcess、编码 还是 损坏输入 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QProcess -> 编码 -> 损坏输入 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 5:性能观察 ​

**场景。**围绕 编码 建一个很小的案例,不要一开始就放进完整业务系统。用小规模和压力规模各跑一次,区分算法成本、同步成本、I/O 成本和工具链配置成本。

**边界。**先判断这里讨论的是 编码、损坏输入 还是 QDataStream 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 编码 -> 损坏输入 -> QDataStream -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 6:生命周期 ​

**场景。**围绕 损坏输入 建一个很小的案例,不要一开始就放进完整业务系统。标出资源创建、转移、共享、停止和销毁的顺序,特别关注错误返回和提前退出路径。

**边界。**先判断这里讨论的是 损坏输入、QDataStream 还是 schema version 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 损坏输入 -> QDataStream -> schema version -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 7:诊断证据 ​

**场景。**围绕 QDataStream 建一个很小的案例,不要一开始就放进完整业务系统。保留命令、日志、符号、栈、测试输出或截图,让结论可以被另一个环境重新验证。

**边界。**先判断这里讨论的是 QDataStream、schema version 还是 QSaveFile 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QDataStream -> schema version -> QSaveFile -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 8:维护策略 ​

**场景。**围绕 schema version 建一个很小的案例,不要一开始就放进完整业务系统。把一次性经验沉淀到 README、CI、脚本、示例工程或检查表里,避免只存在个人记忆中。

**边界。**先判断这里讨论的是 schema version、QSaveFile 还是 QProcess 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> schema version -> QSaveFile -> QProcess -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 9:版本演进 ​

**场景。**围绕 QSaveFile 建一个很小的案例,不要一开始就放进完整业务系统。为未来变更预留兼容策略:版本号、特性位、弃用窗口、迁移脚本和回滚入口。

**边界。**先判断这里讨论的是 QSaveFile、QProcess 还是 编码 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QSaveFile -> QProcess -> 编码 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 10:最小消费者 ​

**场景。**围绕 QProcess 建一个很小的案例,不要一开始就放进完整业务系统。从使用者角度写一个小程序或小工程,只依赖公开接口,验证安装包、头文件和运行时行为。

**边界。**先判断这里讨论的是 QProcess、编码 还是 损坏输入 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QProcess -> 编码 -> 损坏输入 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 11:边界复盘 ​

**场景。**围绕 编码 建一个很小的案例,不要一开始就放进完整业务系统。用一张表说明问题发生在源码、编译、链接、加载、运行、关闭或发布中的哪一层。

**边界。**先判断这里讨论的是 编码、损坏输入 还是 QDataStream 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 编码 -> 损坏输入 -> QDataStream -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 12:反例训练 ​

**场景。**围绕 损坏输入 建一个很小的案例,不要一开始就放进完整业务系统。写出一个看似能工作但不可维护的方案,再说明它在规模、团队协作或发布时会怎样失败。

**边界。**先判断这里讨论的是 损坏输入、QDataStream 还是 schema version 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 损坏输入 -> QDataStream -> schema version -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 13:最小可复现样例 ​

**场景。**围绕 QDataStream 建一个很小的案例,不要一开始就放进完整业务系统。把问题压缩到一个可以提交给同事的目录,保留源码、构建命令、版本输出和预期现象。

**边界。**先判断这里讨论的是 QDataStream、schema version 还是 QSaveFile 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QDataStream -> schema version -> QSaveFile -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 14:接口边界 ​

**场景。**围绕 schema version 建一个很小的案例,不要一开始就放进完整业务系统。写清调用方能依赖什么、不能依赖什么,并把隐式假设转换成命名函数、配置项或测试。

**边界。**先判断这里讨论的是 schema version、QSaveFile 还是 QProcess 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> schema version -> QSaveFile -> QProcess -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 15:失败注入 ​

**场景。**围绕 QSaveFile 建一个很小的案例,不要一开始就放进完整业务系统。故意制造一个常见错误,让日志、断言或测试先失败,再用修复后的证据说明规则生效。

**边界。**先判断这里讨论的是 QSaveFile、QProcess 还是 编码 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QSaveFile -> QProcess -> 编码 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 16:跨平台差异 ​

**场景。**围绕 QProcess 建一个很小的案例,不要一开始就放进完整业务系统。至少比较 Windows、Linux 或不同编译器下的一个差异,记录差异属于标准、实现还是平台约定。

**边界。**先判断这里讨论的是 QProcess、编码 还是 损坏输入 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QProcess -> 编码 -> 损坏输入 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 17:性能观察 ​

**场景。**围绕 编码 建一个很小的案例,不要一开始就放进完整业务系统。用小规模和压力规模各跑一次,区分算法成本、同步成本、I/O 成本和工具链配置成本。

**边界。**先判断这里讨论的是 编码、损坏输入 还是 QDataStream 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 编码 -> 损坏输入 -> QDataStream -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 18:生命周期 ​

**场景。**围绕 损坏输入 建一个很小的案例,不要一开始就放进完整业务系统。标出资源创建、转移、共享、停止和销毁的顺序,特别关注错误返回和提前退出路径。

**边界。**先判断这里讨论的是 损坏输入、QDataStream 还是 schema version 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 损坏输入 -> QDataStream -> schema version -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 19:诊断证据 ​

**场景。**围绕 QDataStream 建一个很小的案例,不要一开始就放进完整业务系统。保留命令、日志、符号、栈、测试输出或截图,让结论可以被另一个环境重新验证。

**边界。**先判断这里讨论的是 QDataStream、schema version 还是 QSaveFile 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QDataStream -> schema version -> QSaveFile -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 20:维护策略 ​

**场景。**围绕 schema version 建一个很小的案例,不要一开始就放进完整业务系统。把一次性经验沉淀到 README、CI、脚本、示例工程或检查表里,避免只存在个人记忆中。

**边界。**先判断这里讨论的是 schema version、QSaveFile 还是 QProcess 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> schema version -> QSaveFile -> QProcess -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 21:版本演进 ​

**场景。**围绕 QSaveFile 建一个很小的案例,不要一开始就放进完整业务系统。为未来变更预留兼容策略:版本号、特性位、弃用窗口、迁移脚本和回滚入口。

**边界。**先判断这里讨论的是 QSaveFile、QProcess 还是 编码 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QSaveFile -> QProcess -> 编码 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 22:最小消费者 ​

**场景。**围绕 QProcess 建一个很小的案例,不要一开始就放进完整业务系统。从使用者角度写一个小程序或小工程,只依赖公开接口,验证安装包、头文件和运行时行为。

**边界。**先判断这里讨论的是 QProcess、编码 还是 损坏输入 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> QProcess -> 编码 -> 损坏输入 -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 23:边界复盘 ​

**场景。**围绕 编码 建一个很小的案例,不要一开始就放进完整业务系统。用一张表说明问题发生在源码、编译、链接、加载、运行、关闭或发布中的哪一层。

**边界。**先判断这里讨论的是 编码、损坏输入 还是 QDataStream 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 编码 -> 损坏输入 -> QDataStream -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

工程切片 24:反例训练 ​

**场景。**围绕 损坏输入 建一个很小的案例,不要一开始就放进完整业务系统。写出一个看似能工作但不可维护的方案,再说明它在规模、团队协作或发布时会怎样失败。

**边界。**先判断这里讨论的是 损坏输入、QDataStream 还是 schema version 的责任;如果三者混在一起,先把输入、输出和所有权拆开。

text
input -> 损坏输入 -> QDataStream -> schema version -> observable result
1

**验证。**记录一条能重复运行的命令或测试,并写明成功输出和失败输出。只说“本机能跑”不够,至少要记录工具版本、构建类型和关键参数。

**常见错误。**把偶然通过当成规则、把私有实现当成公开契约、或者让错误路径绕开清理逻辑,都会让本篇主题在真实项目里变得不可维护。

**复盘问题。**如果明天换一个编译器、Qt 版本、插件版本、输入规模或发布目录,这个结论是否仍成立?不成立时,应该由文档、测试还是 CI 给出提示?

本篇收束 ​

掌握《Qt 数据、I/O 与序列化兼容》的标志,不是记住所有名词,而是能把 QDataStream、schema version、QSaveFile、QProcess、编码、损坏输入 放进一条可验证的工程链路。 先用最小样例建立判断,再用测试和脚本固定判断,最后把失败证据留给未来的自己和团队。

最后更新于:

Pager
下一篇← C++ 编程 / C++ Programming

持续记录,持续成长

Copyright © Tidenflow