
json 标准格式不支持直接追加,但可通过 json lines(jsonl)格式实现每行一条独立 json 记录,从而安全地追加、读取和管理结构化数据。
json 标准格式不支持直接追加,但可通过 json lines(jsonl)格式实现每行一条独立 json 记录,从而安全地追加、读取和管理结构化数据。
在 Python 中,直接对标准 JSON 文件使用 'a'(append)模式写入会导致文件内容变为多个连续的 JSON 对象(如 [...] [...] [...]),这违反了 JSON 规范——合法的 JSON 文档必须且仅能有一个顶层值。因此调用 json.load() 时会抛出 JSONDecodeError: Extra data 错误,因为解析器在读完第一个 JSON 后发现后续还有未预期的数据。
正确方案:采用 JSON Lines(.jsonl)格式
JSONL 是一种轻量级流式格式,要求每行恰好包含一个合法的 JSON 值(对象、数组、字符串、数字等),行间以 \n 分隔。它天然支持追加写入,且可逐行解析,兼顾可读性与实用性。
✅ 推荐实现方式如下:
import json
def write_jsonl(tasks_list, filename='tasks.jsonl'):
"""将任务列表作为单行 JSON 追加到文件"""
with open(filename, 'a', encoding='utf-8') as f:
f.write(json.dumps(tasks_list, ensure_ascii=False) + '\n')
def read_jsonl(filename='tasks.jsonl'):
"""逐行读取并解析所有 JSONL 记录,返回列表"""
records = []
try:
with open(filename, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
line = line.strip()
if not line: # 跳过空行
continue
try:
record = json.loads(line)
records.append(record)
except json.JSONDecodeError as e:
print(f"警告:第 {line_num} 行 JSON 解析失败 — {e}")
continue
except FileNotFoundError:
return [] # 文件不存在时返回空列表,避免中断
return records
# 示例用法
if __name__ == "__main__":
sample_tasks = [
["Task1", "c:/data/file1.txt", "Desc1", 15, ["x", "y"], ""],
["Task2", "c:/data/file2.log", "Desc2", 8, ["z"], "active"]
]
# 多次追加(模拟动态更新)
write_jsonl(sample_tasks)
write_jsonl([["Task3", "c:/tmp/notes.md", "Urgent", 5, [], "pending"]])
# 安全读取全部历史记录
all_data = read_jsonl()
print(f"共加载 {len(all_data)} 条记录:")
for i, entry in enumerate(all_data, 1):
print(f" [{i}] {entry[0]} → {entry[1]} (状态: {entry[-1]})")
? 关键注意事项:
- ✅ 使用 json.dumps(...) + 手动换行(或 print(..., file=f)),而非 json.dump(),因后者不自动添加分隔符;
- ✅ 读取时务必逐行处理,并加入异常捕获,防止单条损坏数据导致整个文件不可读;
- ✅ 若需支持「删除」或「更新」某条记录,JSONL 本身不提供随机访问能力——此时建议改用 SQLite(轻量、ACID、支持 CRUD)或内存缓存 + 全量重写(适用于小数据量);
- ✅ 生产环境推荐使用 .jsonl 作为扩展名,并确保编码统一为 UTF-8(encoding='utf-8');
- ❌ 避免混用 'w' 和 'a' 模式操作同一 JSON 文件,也不要在未清空时重复 json.dump(...) 到 'a' 文件。
总结:当需求是“可追加的结构化日志/事件流/任务队列”时,JSONL 是比传统 JSON 更合适的选择;它简单、高效、跨语言兼容,且完美适配 Python 的文件 I/O 模型。











