Go解析json遇到了大數(shù)字窟社、不定格式等特殊情況,在此做了一個整理绪钥。
Unmarshal vs Decode
選擇哪個要視輸入而定灿里。
json.Unmarshal
操作對象是一個 []byte
,也就意味著被處理的JSON要全部加載到內(nèi)存程腹。如果有一個加載完的JSON使用json.Unmarshal
會快一些匣吊。
json.Decoder
操作的是一個stream
,或者其他實現(xiàn)了io.Reader
接口的類型跪楞。意味著可以在接收或傳輸?shù)耐瑫r對其進行解析缀去。當處理一組較大數(shù)據(jù)時無需重新copy整個JSON到內(nèi)存中侣灶。
最好的選擇辦法如下:
- 如果數(shù)據(jù)來自一個
io.Reader
或者需要從一個stream
中讀取數(shù)據(jù)甸祭,就選擇json.Decoder
- 如果已經(jīng)將整個JSON加載到內(nèi)存中了就使用
json.Unmarshal
數(shù)字的解析
默認情況下,go對json解析過程中遇到的數(shù)字都會當做float64處理褥影。如果數(shù)字過大會有精度丟失池户。可以使用json.Number來處理凡怎。
Unmarshal
val := `{"id": 100010001000100010001000 }` //26位數(shù)字
var y map[string]json.Number
json.Unmarshal([]byte(val), &y)
fmt.Println(y) //map[id:100010001000100010001000]
z, _ := json.Marshal(struct {
Id json.Number `json:"id"`
}{y["id"]})
fmt.Println(string(z)) //{"id":100010001000100010001000}
Decode
val := `{"id": 100010001000100010001000 }` //26位數(shù)字
val2 := strings.NewReader(val) //先轉成io.Reader
d := json.NewDecoder(val2)
d.UseNumber() //標記使用josn.Number
var x map[string]interface{}
if err := d.Decode(&x); err != nil {
panic(err)
}
fmt.Printf("%#v\n", x) //相應值的Go語法表示
newJson, _ := json.Marshal(x)
fmt.Println(string(newJson)) //json.Number編組結果
輸出結果:
map[string]interface {}{"id":"100010001000100010001000"}
{"id":100010001000100010001000}
使用json.Decoder
只能操作io.Reader
類型的JSON數(shù)據(jù)校焦。
不定類型的解析
有時候遇到字段不定的JSON,需要一邊判斷一邊解析统倒。如:
t1 := `{"type":"a", id:"aaa"}`
t2 := `{"type":"b", id:22222}`
解組到interface{}
可以先統(tǒng)一解組到interface{} 然后判斷關鍵字段再進行后續(xù)處理寨典。
type Data struct {
Type string `json:"type"`
Id interface{} `json:"id"`
}
func decode(t string) {
var x Data
err := json.Unmarshal([]byte(t), &x)
if err != nil {
panic(err)
}
if x.Type == "a" {
fmt.Println(x.Id.(string))
} else {
fmt.Println(x.Id.(float64)) //json解析中number默認作為float64解析
}
}
func main() {
t1 := `{"type":"a", "id":"aaa"}`
t2 := `{"type":"b", "id":22222}`
decode(t1)
decode(t2)
}
結果
aaa
22222
使用json.RawMessage
使用RawMessage便于分步Unmarshal
type Resp struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
type Data struct {
Id json.Number `json:"id"` //處理大數(shù)
}
func main() {
t := `{"type": "a", "data":{"id": 1234567890123456789012345}}`
var x Resp
var y Data
json.Unmarshal([]byte(t), &x)
//進一步解組
if "a" == x.Type {
json.Unmarshal(x.Data, &y)
}
fmt.Println(y.Id)
r, _ := json.Marshal(x)
fmt.Println(string(r))
}