Python 文件与 JSON:保存任务后读回并校验结构
将带中文标题的任务列表保存到 JSON 文件,再读取并校验列表、字段与字段类型,区分 JSON 语法正确和业务数据有效。
本节目标
将带中文标题的任务列表保存到 JSON 文件,再读取并校验列表、字段与字段类型,区分 JSON 语法正确和业务数据有效。
知识与使用场景
JSON 适合交换结构化数据,但能被解析不等于符合业务要求。本节只接受任务列表,每个元素必须是字典,title 必须是非空字符串,done 必须是布尔值。
读写文本文件时明确使用 UTF-8,避免不同电脑的默认编码产生差异。ensure_ascii=False 保留中文可读性,indent 让文件便于检查。它们改变展示方式,不负责消除无效字段或保证业务约束。
练习使用 TemporaryDirectory 生成独立目录,执行结束后自动清理,不覆盖已有文件。真正保存到项目目录时,可以把目标换成 Path('data/tasks.json') 并先创建父目录;同时要考虑备份、失败写入和多进程同时修改。
完整示例
import json
from pathlib import Path
from tempfile import TemporaryDirectory
def validate_tasks(data):
if not isinstance(data, list):
raise ValueError("根节点必须是列表")
for item in data:
if not isinstance(item, dict):
raise ValueError("任务必须是对象")
title = item.get("title")
if not isinstance(title, str) or not title.strip():
raise ValueError("标题必须是非空字符串")
if not isinstance(item.get("done"), bool):
raise ValueError("done必须是布尔值")
return data
tasks = [{"title": "学习JSON", "done": False}]
with TemporaryDirectory() as directory:
path = Path(directory) / "tasks.json"
path.write_text(json.dumps(tasks, ensure_ascii=False, indent=2), encoding="utf-8")
loaded = validate_tasks(json.loads(path.read_text(encoding="utf-8")))
print(loaded[0]["title"])
print(loaded == tasks)预期结果
学习JSON
True运行与逐步理解
示例先序列化再读回,True 说明这份简单任务数据在往返后保持一致。程序中的 False 会在 JSON 中写成 false,读取后再恢复成 Python 布尔对象,不能用字符串 "False" 来代替。
validate_tasks 在遍历前先检查根节点,再逐项检查字段。空列表在本例中合法,额外字段也会保留;这属于明确的宽松策略。如果接入网站时要求只允许固定字段,可进一步拒绝多余键或构造只含允许字段的新字典。
JSON 解码失败会抛 JSONDecodeError,文件不存在会抛 FileNotFoundError。它们应在面向用户的调用层转换为不同提示,不能统统当成空任务列表,否则损坏文件可能被下一次保存覆盖。
常见问题与边界
bool('false')得到 True,不能用它解析 JSON 字符串形式的布尔值。- JSON 对象键是字符串,不要依赖整数键往返后仍是整数。
- write_text 会替换目标文件内容,正式持久化可先写临时文件再原子替换,并设计备份。
- 本例适合小文件,read_text 加 json.loads 会把全文放入内存。
动手练习
分别验证 []、[{"title":"复习","done":"false"}] 和 {"tasks":[]},说明结果。
参考答案
空列表通过;done 是字符串的任务被拒绝;以字典作为根节点也被拒绝,即使它内部含 tasks 列表。本函数的入口契约是任务列表,需要提取正确节点后再验证。
文章回复
0 条公开回复