第 3 章:让数据留下来——JSON 存储与安全替换

实现文件读取、JSON 编解码和临时文件替换,理解一个小项目也应该认真处理的数据安全问题。

已发布文章工程实践入门4 分钟阅读发布于 2026年9月4日更新于 2026年9月4日
文章目录
  1. 为什么第一版选择 JSON
  2. 读取文件
  3. 不要直接覆盖旧数据
  4. 数据文件放在哪里
  5. 本章验收
项目路线Go 本地待办清单 CLI3 / 5
  1. 00项目总览
  2. 01第 1 章:先定义完成——需求、边界与验收标准准备
  3. 02第 2 章:搭起骨架——任务模型与程序边界实现
  4. 03第 3 章:让数据留下来——JSON 存储与安全替换实现
  5. 04第 4 章:完成核心功能——添加、查看、完成与删除实现
  6. 05第 5 章:把项目交付出去——测试、构建与复盘验证
LOCAL NOTE高亮并记笔记
0 / 1000 · 只保存在这台设备
READER NOTES第 3 章:让数据留下来——JSON 存储与安全替换》的本机笔记

为什么第一版选择 JSON

数据库擅长并发、查询和约束,但它会引入安装、连接和迁移。这个项目只有一个本地用户,任务数量也很少,因此 JSON 更符合当前问题规模。

选择简单方案不等于随便写。我们仍然要区分“文件不存在”和“文件已经损坏”:前者代表第一次运行,后者代表数据异常。

读取文件

func (store Store) Load() ([]Task, error) {
    body, err := os.ReadFile(store.Path)
    if errors.Is(err, os.ErrNotExist) {
        return []Task{}, nil
    }
    if err != nil {
        return nil, fmt.Errorf("读取任务文件: %w", err)
    }
    if len(body) == 0 {
        return []Task{}, nil
    }
    var tasks []Task
    if err = json.Unmarshal(body, &tasks); err != nil {
        return nil, fmt.Errorf("解析任务文件: %w", err)
    }
    return tasks, nil
}

注意损坏 JSON 会直接返回错误。程序不会假装任务为空,更不会在下一次保存时覆盖原文件。

不要直接覆盖旧数据

如果使用 os.WriteFile(store.Path, body, 0o600),写到一半断电或磁盘空间耗尽,旧文件可能已经被截断。更稳妥的流程是:

JSON 安全替换流程

  1. 在目标目录创建临时文件。
  2. 写入完整 JSON。
  3. 调用 Sync 请求同步落盘。
  4. 关闭临时文件。
  5. 用临时文件替换目标文件。

核心代码如下:

temporary, err := os.CreateTemp(directory, ".tasks-*.tmp")
if err != nil {
    return fmt.Errorf("创建临时文件: %w", err)
}
temporaryPath := temporary.Name()
defer os.Remove(temporaryPath)

if _, err = temporary.Write(body); err != nil {
    temporary.Close()
    return fmt.Errorf("写入临时文件: %w", err)
}
if err = temporary.Sync(); err != nil {
    temporary.Close()
    return fmt.Errorf("同步临时文件: %w", err)
}

示例为了兼容 Windows,在重命名前会移除旧目标文件。这不是面向高并发场景的事务存储,但比直接边截断边写入更安全,也让失败阶段更清晰。

数据文件放在哪里

默认路径是:

~/.xiaoai-todo/tasks.json

测试和临时体验可以覆盖:

$env:TODO_DATA_FILE="$PWD/test-tasks.json"
go run . add "验证 JSON 存储"

环境变量把“程序行为”和“运行位置”分开,不必为了测试修改源码。

本章验收

连续执行两次 add,关闭程序后运行 list。任务仍然存在,并且数据文件是可读的格式化 JSON。手动把文件改成错误内容后,程序应提示“解析任务文件”,而不是返回空列表。

JARVIS · 当前文章

有哪里没看懂?可以只问这篇。

Jarvis 会限定在《第 3 章:让数据留下来——JSON 存储与安全替换》及其公开关联内容中检索,并把引用定位回原文章节。

JARVIS / ARTICLE针对《第 3 章:让数据留下来——JSON 存储与安全替换》提问
当前范围第 3 章:让数据留下来——JSON 存储与安全替换不会悄悄扩大到全站
0 / 1000

准备好了。当前只会围绕第 3 章:让数据留下来——JSON 存储与安全替换回答。

RELATED BUILDS

关联项目

Go 本地待办清单 CLI

使用 Go 标准库完成一个支持添加、查看、完成和删除任务的命令行工具,并通过 JSON 文件持久化、自动化测试和跨平台构建形成完整交付闭环。

implementation积极维护

READER SIGNAL

这篇内容对你有帮助吗?

不需要登录。你的反馈会直接进入作者待处理列表。