如何用Go的encoding/json解码无数组包裹的JSON流?
解决换行分隔JSON对象的流式解码问题
你的问题核心在于:你想用encoding/json的数组流式解析方式,但你的数据根本不是JSON数组(缺少[]包裹),而是多个独立的JSON对象用逗号和换行分隔。Decoder.Token()一开始就期望读到数组的[,自然会抛出“not at beginning of value”错误。
下面给你两种靠谱的解决思路,对应不同的数据格式情况:
情况1:数据是严格的JSON Lines(每行一个JSON对象,无逗号)
如果你的数据是每行一个完整的JSON对象(没有多余的逗号),那处理起来最简单——直接循环调用Decode直到遇到EOF就行,因为json.Decoder会自动跳过换行、空格这类空白字符:
package main import ( "encoding/json" "fmt" "io" "log" "strings" ) func main() { // 去掉了每个对象后面的逗号,变成标准JSON Lines格式 const jsonStream = ` {"Name": "Ed", "Text": "Knock knock."} {"Name": "Sam", "Text": "Who's there?"} {"Name": "Ed", "Text": "Go fmt."} {"Name": "Sam", "Text": "Go fmt who?"} {"Name": "Ed", "Text": "Go fmt yourself!"} ` type Message struct { Name, Text string } dec := json.NewDecoder(strings.NewReader(jsonStream)) // 循环解码每个对象,直到EOF for { var m Message err := dec.Decode(&m) if err != nil { if err == io.EOF { break // 数据处理完毕,退出循环 } log.Fatal(err) } fmt.Printf("%v: %v\n", m.Name, m.Text) } }
情况2:数据带逗号分隔(像你的示例那样)
如果你的数据每个对象后面都带逗号,那需要额外处理逗号这个分隔符——因为逗号不是合法的JSON值,Decode遇到它会报错。我们可以用Token()方法先读取并跳过逗号,再解码对象:
package main import ( "encoding/json" "fmt" "io" "log" "strings" ) func main() { const jsonStream = ` {"Name": "Ed", "Text": "Knock knock."}, {"Name": "Sam", "Text": "Who's there?"}, {"Name": "Ed", "Text": "Go fmt."}, {"Name": "Sam", "Text": "Go fmt who?"}, {"Name": "Ed", "Text": "Go fmt yourself!"} ` type Message struct { Name, Text string } dec := json.NewDecoder(strings.NewReader(jsonStream)) for { // 先读取一个token,判断是对象开头还是逗号 t, err := dec.Token() if err != nil { if err == io.EOF { break } log.Fatal(err) } // 如果是对象的{,退回去让Decode完整解析整个对象 if delim, ok := t.(json.Delim); ok && delim == '{' { dec.UnreadToken() var m Message if err := dec.Decode(&m); err != nil { log.Fatal(err) } fmt.Printf("%v: %v\n", m.Name, m.Text) } // 如果是逗号,直接跳过,继续下一轮循环 } }
这个思路的核心是:不再把数据当成数组来解析,而是逐个处理每个独立的JSON对象,同时跳过用来分隔对象的逗号。
内容的提问来源于stack exchange,提问作者Jay Doh
相关产品推荐
相关产品推荐

