DevCN
菜单
全部文章快讯开发科技深度热点

Go 文件与JSON:把任务写入磁盘并读回验证

完成对象编码、文件写入、读取与解码的完整小流程,逐步检查错误,并明确文件路径与数据格式分别承担的职责。


本节目标

完成对象编码、文件写入、读取与解码的完整小流程,逐步检查错误,并明确文件路径与数据格式分别承担的职责。

前置知识

了解结构体、函数和error处理。示例使用临时目录,不会覆盖当前目录中的同名文件。

准备与运行

在一个新的练习目录执行以下命令。目录名可以修改;若该目录已经初始化过模块,不要重复执行go mod init。

mkdir go-lesson-11
cd go-lesson-11
go mod init example.com/devcn/lesson11

将下方完整代码保存为当前目录的main.go,然后执行:

go fmt ./...
go run .

先用go version确认工具链可用。本例在Go 1.25.7、macOS ARM64环境验证,只使用标准库;没有测试所有操作系统和Go版本。

核心概念

内存中的结构体不能直接当作文件内容写入。json.Marshal把导出的字段编码为字节;字段标签决定JSON键名,Title使用title作为外部名称。os.WriteFile负责把这些字节保存到指定路径,两步各自可能失败。

读取时执行相反过程:先从磁盘取得字节,再用json.Unmarshal解析到目标变量。解码传入&task,是为了让函数更新这个变量,而不是只拿到它的值副本。

示例用MkdirTemp创建独立目录,并用defer安排清理。路径通过filepath.Join组合,减少手工拼接分隔符造成的平台差异。

完整示例

package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
)

type Task struct {
	Title string `json:"title"`
}

func run() error {
	dir, err := os.MkdirTemp("", "devcn-go-")
	if err != nil {
		return err
	}
	defer os.RemoveAll(dir)
	data, err := json.Marshal(Task{Title: "复习"})
	if err != nil {
		return err
	}
	path := filepath.Join(dir, "task.json")
	if err = os.WriteFile(path, data, 0600); err != nil {
		return err
	}
	data, err = os.ReadFile(path)
	if err != nil {
		return err
	}
	var task Task
	if err = json.Unmarshal(data, &task); err != nil {
		return err
	}
	fmt.Println(task.Title)
	return nil
}
func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

运行后应得到:

复习

代码如何工作

run函数负责整个流程,出现错误立即向调用方返回。只有所有步骤成功,才打印从文件恢复的Title。这样可以确认输出确实经过了编码、磁盘和解码,而不是直接打印原对象。

main负责处理最终失败:向标准错误输出信息,并使用非零退出码结束。defer放在run内,所以run返回时先进行目录清理,随后main才可能执行os.Exit。

写入时指定0600权限,主要用于类Unix系统上限制新文件的访问;不要把它当作跨平台访问控制的完整实现。示例只处理一个很小的文件,适合先理解API调用顺序。

常见错误与边界

  • 结构体字段小写开头时,默认JSON编码不会将它作为导出字段处理。
  • 无效JSON应返回错误,不要忽略后使用可能尚未正确填充的对象。
  • 整文件读写会把数据放入内存,大文件需要考虑流式处理。
  • WriteFile不是事务系统,也不自动提供故障时的原子替换保证;生产配置另需考虑备份、临时文件替换和并发写入。

练习

增加Done布尔字段并设为true;在读回后同时打印Title与Done,再用无效JSON测试失败路径。

参考答案

字段定义改为:

type Task struct {
    Title string `json:"title"`
    Done  bool   `json:"done"`
}

编码输入使用Task{Title: "复习", Done: true},读回后fmt.Println(task.Title, task.Done)应得到“复习 true”。

另用json.Unmarshal([]byte("{"), &task)检查无效输入:应得到非nil错误;不要继续把task当作有效数据。

下载推广海报

文章推广海报

《Go 文件与JSON:把任务写入磁盘并读回验证》完整推广海报
DISCUSSION

文章回复

0 条公开回复
未登录回复需要审核后公开
还没有回复,欢迎参与讨论。