Golang解析json的特殊情况处理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang解析json的特殊情况处理相关的知识,希望对你有一定的参考价值。
参考技术A Go解析json遇到了大数字、不定格式等特殊情况,在此做了一个整理。选择哪个要视输入而定。
json.Unmarshal 操作对象是一个 []byte ,也就意味着被处理的JSON要全部加载到内存。如果有一个加载完的JSON使用 json.Unmarshal 会快一些。
json.Decoder 操作的是一个 stream ,或者其他实现了 io.Reader 接口的类型。意味着可以在接收或传输的同时对其进行解析。当处理一组较大数据时无需重新copy整个JSON到内存中。
最好的选择办法如下:
默认情况下,go对json解析过程中遇到的数字都会当做float64处理。如果数字过大会有精度丢失。可以使用json.Number来处理。
输出结果:
使用 json.Decoder 只能操作 io.Reader 类型的JSON数据。
有时候遇到字段不定的JSON,需要一边判断一边解析。如:
可以先统一解组到interface 然后判断关键字段再进行后续处理。
结果
使用RawMessage便于分步Unmarshal
原文链接
Golang ---json解析
golang官方为我们提供了标准的json解析库–encoding/json
,大部分情况下,使用它已经够用了。不过这个解析包有个很大的问题–性能。它不够快,如果我们开发高性能、高并发的网络服务就无法满足,这时就需要高性能的json解析库,目前性能比较高的有json-iterator
和easyjson
。
现在我们需要引进一个高性能的json解析库,这里以json-iterator
为例,但是我们全部换掉又不放心,所以可以先小范围的测试下,这时候我们就需要两个解析库并存,那么这时候我们如何选择我们需要的解析库编译和运行呢?
解决上面问题的办法就是条件编译。Go语言为我们提供了基于tags的编译约束来解决这个问题。
统一JSON库
我们先举个例子看看结果。现在我们需要两个库并存,所以我们先得统一这两个库的用法(参考适配器模式),这里我们使用一个自定义的json
包来适配encoding/json
和json-iterator
。
json/json.go
// +build !jsoniter package json import ( "encoding/json" "fmt" ) func MarshalIndent(v interface, prefix, indent string) ([]byte, error) fmt.Println("Use [encoding/json] package") return json.MarshalIndent(v,prefix,indent)
json/jsoniter.go
// +build jsoniter package json import ( "fmt" "github.com/json-iterator/go" ) var ( json = jsoniter.ConfigCompatibleWithStandardLibrary ) func MarshalIndent(v interface, prefix, indent string) ([]byte, error) fmt.Println("Use [jsoniter] package") return json.MarshalIndent(v,prefix,indent)
目录结构如下:
json
├── json.go
└── jsoniter.go
例子中以MarshalIndent
函数为例,我们发现json
包下的两个go文件中都有MarshalIndent
函数的定义,并且签名一致,但是它们又是使用不同的json解析库实现,这就是我们统一适配包装后的结果,调用统一了。
Demo演示
为了区分调用的是哪个json库的具体实现,打印日志,以便区分。现在我们使用json.MarshalIndent
测试一下。
package main import ( "fmt" "json" ) func main() u := user"Mike", 30 b, err := json.MarshalIndent(u, "", " ") if err != nil fmt.Println(err) else fmt.Println(string(b)) type user struct Name string Age int
使用很简单,把一个user
结构体对象转为json字符串,并打印出来。我们运行go run main.go
看看结果。
Use [encoding/json] package "Name": "Mike", "Age": 30
保持我们默认使用encoding/json
库的方式不变。现在我们换一种编译运行方式:
go run -tags=jsoniter main.go
这次运行和上次不同的地方在于我们加了-tags=jsoniter
,然后就使用了json-iterator
这个json库,这就是选择性的条件编译,达到了我们小部分测试新的json库的目的。
条件编译
我们发现,条件编译的关键在于-tags=jsoniter
,也就是-tags
这个标志,这就是Go语言为我们提供的条件编译的方式之一。
好了,回过头来看我们刚开始时json/json.go
、json/jsoniter.go
这两个Go文件的顶部,都有一行注释:
// +build !jsoniter
// +build jsoniter
这两行是Go语言条件编译的关键。+build
可以理解为条件编译tags的声明关键字,后面跟着tags的条件。
// +build !jsoniter
表示,tags不是jsoniter
的时候编译这个Go文件。 // +build jsoniter
表示,tags是jsoniter
的时候编译这个Go文件。
也就是说,这两种条件是互斥的,只有当tags=jsoniter
的时候,才会使用json-iterator
,其他情况使用encoding/json
。
小结
利用条件编译,我们实现了灵活选择json解析库的目的,且tags只是其中的一部分,Go语言还可以根据Go文件后缀进行条件编译。
以上是关于Golang解析json的特殊情况处理的主要内容,如果未能解决你的问题,请参考以下文章