Files
scuc-qt-course/docs/teaching/examples/file_io_demo/README.md
T
张宗平 01b264fe97 Day4 教学示例补三个:QDialog 综合 / QLineEdit 小眼睛 / 文件 IO(+顶层构建注册)
- qdialog_showcase:wiki「6 对话框 QDialog」6.2–6.5 综合演示。含两套实现:
  · Designer 表单版(dialog.{h,cpp,ui} + resources.qrc + source.gif,QMovie 播 GIF)
  · 纯代码版(qt_dialog_showcase.cpp,单文件,QWidget 布满按钮逐个演示 QDialog 行为)
- lineedit_eye_toggle:子类化 QLineEdit,paintEvent 自绘小眼睛、mouseEvent 命中切换
  echoMode,并与内置 clear button 动态避让(读 objectName=="clearButton" 子 widget 几何)。
  含独立子目录 CMakeLists.txt 供单独打开(顶层 add_subdirectory 不递归)。
- file_io_demo:QFile/QTextStream/QDataStream/QFileInfo/QDir/QTextCodec/QJson 五主题
  综合示例,每个按钮产出一个文件落到 demo_output/ 便于课堂手动查看。

构建注册:examples/CMakeLists.txt 用 add_teaching_example 注册前两个纯代码示例,
mandelbrot 多源文件单独 add_executable;calculator_mainwindow_qss 加 themes.qrc 与
AUTORCC;all_teaching_examples 依赖列表同步补齐。

附 lineedit_eye_toggle 设计文档(docs/superpowers/specs)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 16:51:09 +08:00

6.2 KiB
Raw Blame History

qt_file_io_demo —— Qt5 文件操作教学示例

一个 QWidget 布满按钮,分 5 个主题演示 Qt5 文件操作。每个按钮产生一个文件,落到 可执行文件同目录的 demo_output/ 子目录下,界面顶部 statusLabel 始终显示绝对路径, 方便课堂逐个手动打开查看文件内容。

这是对仓库 json_io(控制台、仅内存序列化)的 GUI 补充:把 QJson + 真实文件 I/O 与其它文件操作主题一起,放进一个可点击演示的界面。

构建

仓库统一构建(走 examples/CMakeLists.txtadd_teaching_example):

cmake -S . -B build -G Ninja -DBUILD_QT_PART=ON \
      -DCMAKE_PREFIX_PATH=$PWD/.qt514/5.14.2/gcc_64 -DCMAKE_BUILD_TYPE=Debug
cmake --build build --target qt_file_io_demo
tools/run_qt.sh qt_file_io_demo

单独打开(用本目录的独立 CMakeLists.txt):

cmake -S . -B build -DCMAKE_PREFIX_PATH=<Qt5.14.2> -DCMAKE_CXX_COMPILER=<g++>
cmake --build build

离屏自动化验证(仿 p03 风格,200ms 自动退出、退出码 0):

QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_file_io_demo

界面布局

┌─ statusLabel(显示绝对路径 + 每个演示的结果摘要)─────────────┐
├─ ① 基础文件操作  QFile 写/读/追加、QFileInfo、QDir            │
├─ ② 字符集编码    UTF-8 / Latin-1 / GBK / UTF-16LE / 乱码对比   │
├─ ③ 文本vs二进制  QTextStream / QDataStream / QIODevice::Text  │
├─ ④ 异常处理      Qt 返回值式 | C++ try/catch(对照)          │
├─ ⑤ QJson 文件    写 / 读 / 改写                                │
├─ [在文件管理器中打开 demo_output]  [清空 demo_output]          │
└──────────────────────────────────────────────────────────────┘

各主题要点与产出文件

① 基础文件操作

按钮 产出文件 要点
QFile 写文本 01_qfile_write.txt QTextStream 写;坑点:Qt5 默认 codec 是系统区域编码(中文 Windows 常为 GBK),写中文必须显式 setCodec("UTF-8")
QFile 读文本 (读上一个) 读端同样要 setCodec("UTF-8"),否则跨平台乱码
追加 vs 覆盖 01_append.txt WriteOnly 每次清空;Append 在末尾追加
QFileInfo 信息 01_fileinfo.txt exists / size / absoluteFilePath / absolutePath
QDir 列目录 entryList(QDir::Files) 列出 demo_output 内文件

② 字符集编码

按钮 产出文件 要点
写 UTF-8 02_utf8.txt QString::toUtf8():中文每字 3 字节、ASCII 每字 1 字节
写 UTF-8 + BOM 02_utf8_bom.txt 头部 EF BB BF(十六进制可见)
写 Latin-1 02_latin1.txt toLatin1() 只能表 U+0000~U+00FF,中文超出变 ?
写 GBK 02_gbk.txt QTextCodec::codecForName("GBK")未装 CJK codec 插件时返回 nullptr,界面列出当前可用编码并给出提示。本仓库 MinGW Qt 未含 plugins/codecs/,故此按钮走降级提示(这本身就是教学点);如需真正写 GBK,用 Qt Maintenance Tool 勾选安装 codecs 插件,或把 plugins/codecs/ 拷到 Qt 的 plugins 目录
写 UTF-16LE 02_utf16le.txt 手动写 FF FE BOM + 每字符固定 2 字节(低字节在前)
乱码:错码读回 (读 02_utf8.txt UTF-8 字节用 Latin-1 强解 → mojibake,说明「读写编码须一致」

用编辑器(VS Code / Notepad++)切换编码打开这些文件,可直观看到「同一段中文在不同编码下的字节差异」与乱码成因。

③ 文本方式 vs 二进制方式

按钮 产出文件 要点
文本写结构 03_struct_text.txt QTextStreamname=张三 / age=20 / score=95.5:可读但格式松散
二进制写结构 03_struct_bin.dat QDataStreamqint32 + double + QString:紧凑、带类型、可精确还原(程序内立即读回验证)
对比大小 QFileInfo 报告两文件字节数;用十六进制工具看 .dat 内部布局
QIODevice::Text 换行 03_nl_text.txt / 03_nl_bin.txt Windows 下 Text 标志把 \n\r\n,不加则原样 \nLinux 下两者相同

QDataStream 务必 setVersion(Qt_5_14),否则 Qt 升级后二进制格式可能不兼容。

④ 异常与错误处理(两范式对照)

按钮 要点
Qt: 打开不存在文件 Qt 范式open() 返回 false + error() / errorString(),不抛异常
Qt: 只读模式写 只读 QFilewrite() 返回 -1 + errorString()
C++: ifstream 异常 C++ 范式in.exceptions(failbit|badbit) 后打开失败抛 std::ios_base::failuretry/catch 捕获
C++: throw + catch 自定义异常 + catch 顺序(派生类在前、基类在后)
JSON: 损坏解析 04_broken.jsonQJsonDocument::fromJson 不抛异常,用 QJsonParseError 拿出错偏移与描述

核心对照:Qt 几乎不用 C++ 异常,错误经返回值/API 暴露;标准库流默认也不抛,需显式开启。 教学 LLVM 式「异常 vs 返回值」两种错误处理哲学的绝佳切入点。

⑤ QJson 文件读写

按钮 产出文件 要点
写 JSON 文件 05_student.json QJsonObject + QJsonArrayQJsonDocument::toJson(Indented) → 写文件
读 JSON 文件 (读上一个) fromJsonobject() → 按键取值,toArray() 遍历数组
修改后回写 (覆盖上一个) score、增 grade、删 enrolled,覆盖回写

demo_output 在哪?

QCoreApplication::applicationDirPath() + "/demo_output" —— 即可执行文件旁边tools/run_qt.sh 运行时通常在 build/ 下,所以路径形如 build/qt_file_io_demo 同级。 界面底部「在文件管理器中打开 demo_output」按钮可一键定位。

相关课程点

对应「C++ 方向 Day3」文件与数据格式章节;与 json_io(控制台 QJson 内存演示)、 p03/ch11wiki 的 QFile/QTextStream/QDataStream)互为补充。