数据格式速查

本课程涉及的核心数据格式对比。快速参考——详细讨论见各课程。

一、JSON

属性
全称JavaScript Object Notation
RFCRFC 8259
MIME 类型application/json
文件后缀.json
结构一个完整的 JSON 值:对象 {}、数组 []、字符串、数字、布尔、null
解析整个文件 → JSON.parse()
修改读 → 改 → 写(三次 I/O)
适合场景配置、API 响应、数据交换、需要随机访问任意字段

解析代码

const data = JSON.parse(readFileSync('file.json', 'utf-8'));
console.log(data.key);

二、JSONL(JSON Lines)

属性
全称JSON Lines
别名NDJSON、LDJSON
规范jsonlines.org
文件后缀.jsonl
结构每行一个独立完整的 JSON 值,无最外层包裹
行分隔符\n(LF,Unix 风格)
解析按行拆分 → 逐行 JSON.parse()
修改追加一行即可(一次 I/O)
适合场景日志、消息流、会话记录、事件溯源——持续追加、永不修改历史

核心规则

  1. 每行一个完整 JSON 值
  2. 行内换行符必须转义(\n\\n
  3. 文件编码为 UTF-8
  4. 建议行末不加逗号(它不是 JSON 数组)

解析代码

const lines = readFileSync('file.jsonl', 'utf-8').trim().split('\n');
const records = lines.filter(l => l.trim()).map(JSON.parse);
console.log(records[0].type);

追加代码

const entry = { type: 'user', content: 'hello' };
appendFileSync('file.jsonl', JSON.stringify(entry) + '\n');

常见陷阱

陷阱错误正确做法
空行JSON.parse('') → SyntaxError.filter(l => l.trim())
整体解析JSON.parse(整个文件) → SyntaxError必须逐行 parse
行内换行content 字段含未转义的 \n始终用 JSON.stringify() 序列化

三、JSONL 在本项目中的使用

Claude Code 将每个对话会话存储为 ~/.claude/projects/<encoded-path>/<session-id>.jsonl

消息行示例

用户消息行:
{"type":"user","message":{"content":"帮我写一个函数","timestamp":"..."}}

AI 响应行(含 token 用量):
{"type":"assistant","message":{"content":"好的……","model":"claude-sonnet-4-6","usage":{"input_tokens":42,...}}}

系统命令行:
{"type":"user","message":{"content":"<command-name>/clear</command-name>","timestamp":"..."}}

claude-context-bar 的读取策略

  1. 反向扫描:从最后一行往前找最近的 /clear 命令
  2. 正向扫描:/clear 位置往后收集 sessionCreated、firstMessage、model、totalTokens
  3. 关键点:利用 JSONL 的行结构实现"部分读取"——不需要解析整个文件

四、何时用哪种格式

决策流程:

数据是否需要持续追加?
  ├─ 是 → JSONL
  └─ 否 → 是否需要随机访问任意字段?
            ├─ 是 → JSON
            └─ 否 → 数据量是否非常大(>10MB)?
                      ├─ 是 → JSONL(支持流式读取)
                      └─ 否 → JSON(更简单的工具链)