文件、JSON 与实用脚本
文件、JSON 与实用脚本 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
这一课把前面四课攒的零件拼成一个真工具:扫描本站 content/courses 下的课程元数据,校验 JSON 合法性,坏文件不中断,最后输出一份能定位到具体文件和原因的报告。
问题场景
本站 180 门课的 course.json 全靠人维护,手滑写坏一个 JSON、漏一个必填字段,npm run db:seed 就会在某个深夜导入失败。你需要一个预检脚本:python check_courses.py 一跑,哪个文件、哪一行、什么问题,一屏看全。
这就是「实用脚本」的标准形态:读文件、解析、校验、报告——每一步都用到 P01 的环境、P03 的模块拆分、P04 的异常处理。
核心解释
三个基础件先钉牢:
- pathlib 管路径。
Path("content/courses")拼接用/运算符(p / "python" / "p07-fastapi-basics"),跨平台不用管斜杠;glob("*/course.json")一次列出所有目标文件。 - 编码必须显式。
open(p, encoding="utf-8")写全——Windows 默认编码是 GBK,中文 JSON 不写 encoding 就是乱码或炸 UnicodeDecodeError。写回用json.dump(data, f, ensure_ascii=False, indent=2),中文保持原样而不是\uXXXX。 - 坏文件是常态不是异常。校验工具的生命线是「单个文件失败不影响整体」,P04 的 try/except 在这里第一次派上真正用场。
核心循环长这样:
# check_courses.py
import json
import sys
from pathlib import Path
REQUIRED = ["code", "slug", "title", "track"]
def check_file(path: Path) -> str | None:
"""返回 None 表示通过,否则返回问题描述。"""
try:
data = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError as e:
return f"JSON 解析失败(第{e.lineno}行)"
missing = [k for k in REQUIRED if k not in data]
if missing:
return f"缺少必填字段: {', '.join(missing)}"
return None
def main() -> int:
problems = []
for path in sorted(Path("content/courses").glob("*/*/course.json")):
if err := check_file(path):
problems.append(f"{path.as_posix()}: {err}")
for line in problems:
print("FAIL", line)
print(f"共 {len(problems)} 个问题")
return 1 if problems else 0 # 退出码:有错为 1
if __name__ == "__main__":
sys.exit(main())
示例拆解
制造坏文件再运行验证:
python check_courses.py
# FAIL content/courses/python/p08-request-response-validation/course.json: JSON 解析失败(第3行)
# 共 1 个问题
echo $?
# 1 —— 退出码非 0,可以被 npm script / CI 判定失败
三个设计点值得复述一遍:报告带文件路径 + 行号,拿到就能改,不是笼统一句「有错」;坏文件收集后继续,一次跑出全部问题而不是修一个跑一遍;退出码区分通过与否,脚本才能被别的工具链调用。把目录参数化成 sys.argv,这个脚本就能复用到任何 JSON 目录上。
动手任务
本课实验区有可直接运行的版本(纯标准库,针对临时样例目录校验):
- 给
check_file补充校验:prereqs存在时必须是字符串数组,不合法返回对应描述。 - 把目录改成
sys.argv[1]传入,没有参数时打印用法并返回退出码 2。 - 让报告额外统计「通过数 / 总数」,末尾输出
checked=10 passed=9 failed=1一行汇总。
常见错误
- 不写 encoding 读中文文件:Windows 默认 GBK,轻则乱码重则异常;读写一律显式
encoding="utf-8"。 - 拼接路径用字符串加号:
"dir" + "/" + name在跨平台时埋雷;用Path的/运算符。 - 一个坏文件中断全部:把 json.load 写在循环里不捕获,错一个停一串;逐文件收集错误。
- JSON 写回变成 \uXXXX:忘了
ensure_ascii=False,中文全被转义,diff 里没法看。
检查与复盘
自查清单:
- 脚本能对「好文件、坏 JSON、缺字段」三种情况给出各自准确的报告
- 报告里每条都包含文件路径和可定位的原因
- 退出码行为正确,且说得出它对调用方的意义
参考资料
- pathlib 标准库文档 —— 路径对象与 glob
- json 标准库文档 —— load/dump 参数与异常类型
读完这一课了?
标记完成后,工作台会安排接下来的学习。