# json-iterator使用

特点

  • json-iterator是一款快且灵活的JSON解析器,同时提供JavaGo两个版本。
  • json-iterator是最快的JSON解析器。它最多能比普通的解析器快10倍之多
  • 独特的iterator api能够直接遍历JSON ,极致性能、0内存分配
  • dsljsonjsonparser借鉴了大量代码。

# 1 性能对比

完整报告请看性能评测,对于性能优化是怎么做的有详尽的解释。

# 1.1 Java端性能对比

主流的JSON解析器是非常慢的。Jsoniter Java版本可以比常用的jackson/gson/fastjson快3倍。 如果你需要处理大量的JSON格式的日志,你应该考虑一下用dsl-json或者Jsoniter来节约可观的成本。 根据dsl-json的性能评测,JSON格式序列化和反序列化的速度其实一点都不慢,甚至比thrift/avro还要快。

protobuf-vs-jsoniter

# 1.2 Golang端性能对比

JsoniterGolang版本可以比标准库(encoding/json)快6倍之多。而且这个性能是在不使用代码生成的前提下获得的。

go-benchmark

# 2 下载依赖

go get github.com/json-iterator/go
1

# 3 简单应用示例

# 3.1 序列化Marshal

jsoniter常用序列化函数如下

// 直接把结构体转化成字符串
MarshalToString(v interface{}) (string, error)
//把结构体转化成json,兼容go标准库encoding/json的序列化方法,返回一个字节切片和错误
Marshal(v interface{}) ([]byte, error)
//转化成字节切片,第一个参数是结构体对象,第二个参数是前缀字符串必须为"",第三个参数为缩进表示,只能是空格
MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
1
2
3
4
5
6
package main

import (
	"fmt"
	"github.com/json-iterator/go"
)

// Student 测试转换json的结构体
type Student struct {
	Name    string   `json:"name"`
	Age     int      `json:"age"`
	Address string   `json:"address"`
	Hobby   []string `json:"hobby"`
}

func main() {
	stu := Student{
		Name:    "张三",
		Age:     18,
		Address: "chengdu",
		Hobby:   []string{"football", "swimming", "travel", "sing"},
	}
	// Marshal(v interface{}) ([]byte, error)
	//把结构体转化成json,兼容go标准库encoding/json的序列化方法,返回一个字节切片和错误
	b, err := jsoniter.Marshal(stu)
	if err != nil {
		fmt.Println("transformation error: ", err)
	}
	//输出转化后的字符串
	//{"name":"张三","age":18,"address":"chengdu","hobby":["football","swimming","travel","sing"]}
	fmt.Println(string(b))
	//直接把结构体转化成字符串MarshalToString,这里错误判断省略
	str, _ := jsoniter.MarshalToString(stu)
    //{"name":"张三","age":18,"address":"chengdu","hobby":["football","swimming","travel","sing"]}
	fmt.Println(str)
	//转化成字节切片,第一个参数是结构体对象,第二个参数是前缀字符串必须为"",第三个参数为缩进表示,只能是空格
	b, _ = jsoniter.MarshalIndent(stu, "", " ")
    //输出带格式的字符串
	fmt.Println(string(b))
}
---------------------输出结果--------------------------------
调用了Calc的初始化方法
{"name":"张三","age":18,"address":"chengdu","hobby":["football","swimming","travel","sing"]}
{"name":"张三","age":18,"address":"chengdu","hobby":["football","swimming","travel","sing"]}
{
 "name": "张三",
 "age": 18,
 "address": "chengdu",
 "hobby": [
  "football",
  "swimming",
  "travel",
  "sing"
 ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# 3.2 反序列化Unmarshal

jsoniter常用反序列化函数如下

//把字节切片的JSON格式转换成对应的结构体
Unmarshal(data []byte, v interface{}) error 
//把字符串的JSON格式转换成对应的结构体
UnmarshalFromString(str string, v interface{}) error 
1
2
3
4
package main

import (
	"fmt"
	"github.com/json-iterator/go"
)

// Student 测试转换json的结构体
type Student struct {
	Name    string   `json:"name"`
	Age     int      `json:"age"`
	Address string   `json:"address"`
	Hobby   []string `json:"hobby"`
}

func main() {
	//反序列化给一个结构体
	var stu Student
	var jsonBlob = []byte(`
        {"name": "张三", "Age": 12,"Address":"chengdu","Hobby":["football", "swimming", "travel", "sing"]}
    `)
	//根据字节切片转换成结构体。注意这里传入的是结构体地址
	err := jsoniter.Unmarshal(jsonBlob, &stu)
	if err != nil {
		fmt.Println("unmarshal error: ", err)
	}
	fmt.Printf("根据字节切片转换的结构体数据:%+v\n", stu)

	//根据字节切片转换成结构体
	var students []Student
	var jsonSlice = []byte(`[
        {"name": "张三", "Age": 12,"Address":"chengdu","Hobby":["football", "swimming", "travel", "sing"]},
        {"name": "李四", "Age": 28,"Address":"sichuan","Hobby":["dance", "music"]}
   ]`)
	//根据字节切片转换成结构体。把多个结构体json数据反序列化给结构体切片
	err = jsoniter.Unmarshal(jsonSlice, &students)
	if err != nil {
		fmt.Println("unmarshal error: ", err)
	}
	fmt.Printf("根据字节切片转换的结构体数据:%+v\n", students)
	//根据
	var stu1 Student
	stuStr := `{"name": "张三", "Age": 12,"Address":"chengdu","Hobby":["football", "swimming", "travel", "sing"]`
	//根据字符串转换成结构体。注意这里传入的是结构体地址
	jsoniter.UnmarshalFromString(stuStr, &stu1)
	fmt.Printf("根据字符串转换的结构体数据:%+v\n", stu1)
}
--------------------------------输出结果---------------------------------------
调用了Calc的初始化方法
根据字节切片转换的结构体数据:{Name:张三 Age:12 Address:chengdu Hobby:[football swimming travel sing]}
根据字节切片转换的结构体数据:[{Name:张三 Age:12 Address:chengdu Hobby:[football swimming travel sing]} {Name:李四 Age:28 Address:sichuan Hobby:[dance music]}]
根据字符串转换的结构体数据:{Name:张三 Age:12 Address:chengdu Hobby:[football swimming travel sing]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 4 jsoniter.Get

# 获取深层嵌套JSON结构的值的快速方法

//惰性json实现保持[]byte并延迟解析,把 json 解析为 Any 对象
Get(data []byte, path ...interface{}) Any
//Any通用对象表示
//最简单的json实现持有字节切片,并延迟解析
type Any interface {
	LastError() error
	ValueType() ValueType
	MustBeValid() Any
	ToBool() bool
	ToInt() int
	ToInt32() int32
	ToInt64() int64
	ToUint() uint
	ToUint32() uint32
	ToUint64() uint64
	ToFloat32() float32
	ToFloat64() float64
	ToString() string
	ToVal(val interface{})
	Get(path ...interface{}) Any
	Size() int
	Keys() []string
	GetInterface() interface{}
	WriteTo(stream *Stream)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"fmt"
	jsoniter "github.com/json-iterator/go"
)

// Student 测试转换json的结构体
type Student struct {
	Name    string   `json:"name"`
	Age     int      `json:"age"`
	Address string   `json:"address"`
	Hobby   []string `json:"hobby"`
}

func main() {
	var jsonBlob = []byte(`
        {"name": "张三", "Age": 12,"Address":"chengdu","Hobby":["football", "swimming", "travel", "sing"]}
    `)
	//获取深层嵌套JSON结构的值的快速方法
	//返回一个数组指针
	hobby := jsoniter.Get(jsonBlob, "Hobby")
	fmt.Printf("%T\n",hobby)//*jsoniter.arrayLazyAny
	//获取这个结构体Hobby元素下面的第二个元素值
	str := jsoniter.Get(jsonBlob, "Hobby", 1).ToString()
	fmt.Println(str) //swimming
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 5 NewDecoder

通过流的方式操作json,适用于大文件json

//NewDecoder适用于json/stream NewDecoder API。
//new decoder返回从r读取的新解码器。
//不是json/编码解码器,而是返回一个解码器
//更多信息请参考https://godoc.org/encoding/json#NewDecoder
NewDecoder(reader io.Reader) *Decoder 
1
2
3
4
5
package main

import (
	"fmt"
	"strings"

	"github.com/json-iterator/go"
)

func main() {
	json := jsoniter.ConfigCompatibleWithStandardLibrary
	reader := strings.NewReader(`{"branch":"beta","change_log":"add the rows{10}","channel":"fros","create_time":"2017-06-13 16:39:08","firmware_list":"","md5":"80dee2bf7305bcf179582088e29fd7b9","note":{"CoreServices":{"md5":"d26975c0a8c7369f70ed699f2855cc2e","package_name":"CoreServices","version_code":"76","version_name":"1.0.76"},"FrDaemon":{"md5":"6b1f0626673200bc2157422cd2103f5d","package_name":"FrDaemon","version_code":"390","version_name":"1.0.390"},"FrGallery":{"md5":"90d767f0f31bcd3c1d27281ec979ba65","package_name":"FrGallery","version_code":"349","version_name":"1.0.349"},"FrLocal":{"md5":"f15a215b2c070a80a01f07bde4f219eb","package_name":"FrLocal","version_code":"791","version_name":"1.0.791"}},"pack_region_urls":{"CN":"https://s3.cn-north-1.amazonaws.com.cn/xxx-os/ttt_xxx_android_1.5.3.344.393.zip","default":"http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip","local":"http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip"},"pack_version":"1.5.3.344.393","pack_version_code":393,"region":"all","release_flag":0,"revision":62,"size":38966875,"status":3}`)
	decoder := json.NewDecoder(reader)
	params := make(map[string]interface{})
	err := decoder.Decode(&params)
	if err != nil {
		fmt.Println(err)
	} else {
//map[firmware_list: note:map[CoreServices:map[package_name:CoreServices version_code:76 version_name:1.0.76 md5:d26975c0a8c7369f70ed699f2855cc2e] FrDaemon:map[md5:6b1f0626673200bc2157422cd2103f5d package_name:FrDaemon version_code:390 version_name:1.0.390] FrGallery:map[version_code:349 version_name:1.0.349 md5:90d767f0f31bcd3c1d27281ec979ba65 package_name:FrGallery] FrLocal:map[version_name:1.0.791 md5:f15a215b2c070a80a01f07bde4f219eb package_name:FrLocal version_code:791]] pack_version:1.5.3.344.393 pack_version_code:393 status:3 channel:fros pack_region_urls:map[CN:https://s3.cn-north-1.amazonaws.com.cn/xxx-os/ttt_xxx_android_1.5.3.344.393.zip default:http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip local:http://192.168.8.78/ttt_xxx_android_1.5.3.344.393.zip] release_flag:0 size:3.8966875e+07 md5:80dee2bf7305bcf179582088e29fd7b9 region:all revision:62 change_log:add the rows{10} create_time:2017-06-13 16:39:08 branch:beta]
		fmt.Printf("%+v\n", params)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6 标准库兼容配置

ConfigCompatibleWithStandardLibrary尝试与标准库行为100%兼容配置

package main

import (
	"fmt"
	"github.com/json-iterator/go"
)

// Student 测试转换json的结构体
type Student struct {
	Name    string   `json:"name"`
	Age     int      `json:"age"`
	Address string   `json:"address"`
	Hobby   []string `json:"hobby"`
}

func main() {
	stu := Student{
		Name:    "张三",
		Age:     18,
		Address: "chengdu",
		Hobby:   []string{"football", "swimming", "travel", "sing"},
	}
	//返回与标准库行为100%兼容的配置对象,返回encoding/json的操作对象
	var json = jsoniter.ConfigCompatibleWithStandardLibrary
	b, err := json.Marshal(stu)
	if err != nil {
		fmt.Println("transformation error: ", err)
	}
	fmt.Println(string(b))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 7 更多资料

jsoniter源码

jsoniter中文官网

jsoniter API文档