json.marshalindent 是最轻量可控的 json 格式化方式,应避免 fmt.println 导致多余换行,推荐用 os.stdout.write 输出、双空格缩进,并需处理输入超时、长度限制、编码异常及跨平台问题。

用 json.MarshalIndent 做基础格式化,但别直接 print 到 stdout
命令行管道场景下,json.MarshalIndent 是最轻量、最可控的格式化方式。它不依赖外部工具,也不引入额外依赖,适合嵌入到小型 CLI 工具中。
常见错误是把格式化后字节直接 fmt.Println —— 这会在末尾多加一个换行,破坏管道兼容性(比如接 jq 或 grep 时出错)。
- 始终用
os.Stdout.Write()或fmt.Fprint(os.Stdout, ...)输出原始字节 - 缩进字符推荐用两个空格:
" ",避免 tab 导致某些老工具解析异常 - 如果输入可能含非 UTF-8 字节(如误传二进制),
json.Unmarshal会报invalid character '' looking for beginning of value,需提前检查或忽略 BOM
处理 stdin 输入时必须设超时或限制长度,否则管道挂起
Go 默认读 os.Stdin 是阻塞的。当上游没关流(比如 curl -s URL | yourtool 中 curl 出错未退出),你的程序会永远等下去。
真实场景里,用户不会手动 Ctrl+D,得靠代码主动收口。
立即学习“go语言免费学习笔记(深入)”;
- 用
io.LimitReader(os.Stdin, 10*1024*1024)限制最大读 10MB,防 OOM - 别用
bufio.Scanner默认行为——它按行切分,而 JSON 可能单行超长;改用io.ReadAll+ 长度检查 - 如果想支持“边读边格式化”(如大数组流式 prettify),得用
json.Decoder.Token()手动遍历,但绝大多数 CLI 场景没必要
错误处理要区分 json.SyntaxError 和其他 panic 风险
用户扔过来的很可能不是合法 JSON:少逗号、多逗号、单引号、注释、YAML 混入……这些都会让 json.Unmarshal 失败,但错误类型不同,处理策略也不同。
-
json.SyntaxError含Offset字段,可定位到出错位置,建议输出类似error at byte 123: invalid character ',' after object key -
io.ErrUnexpectedEOF表示流提前结束,常见于网络传输中断,应提示 “incomplete JSON input” 而非泛泛的 “invalid JSON” - 别 recover
panic—— Go 的json包不会 panic,强行包一层反而掩盖真实错误 - 如果想兼容带注释的 JSON(如 VS Code 配置),得先用正则删注释(不推荐)或换用
github.com/tidwall/gjson等库,但那就超出纯标准库范围了
Windows 下换行符和重定向需额外注意 os.Stdin 模式
在 PowerShell 或 cmd 中运行 echo {"a":1} | yourtool.exe,有时会卡住或读到奇怪字符。这不是 Go 的 bug,而是 Windows 控制台默认以文本模式打开 stdin,会把 \r\n 自动转成 \n,还可能缓存不刷新。
- 加一句
os.Stdin = os.NewFile(uintptr(syscall.Stdin), "/dev/stdin")(仅 Windows)强制二进制模式,但需import "syscall" - 更稳妥做法:用
golang.org/x/sys/windows调用SetConsoleMode关闭ENABLE_LINE_INPUT - 测试时优先用
type file.json | yourtool.exe而非echo,避免 shell 层面的转义干扰
管道处理真正麻烦的从来不是格式化本身,而是输入边界模糊、错误反馈太笼统、跨平台行为不一致——这些点不提前压住,上线后第一反应往往是“怎么在客户机器上就不行”。










