路漫漫其修远兮
吾将上下而求索

go学习:json操作

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript 规范的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

encoding/json 是Go语言自带的JSON转换库

json格式化工具:http://tool.oschina.net/codeformat/json

编码

func Marshal(v interface{}) ([]byte, error)

把对象转换为JSON: 

• 布尔型转换为 JSON 后仍是布尔型 , 如true -> true
• 浮点型和整数型转换后为JSON里面的常规数字,如 1.23 -> 1.23
• 字符串将以UTF-8编码转化输出为Unicode字符集的字符串,特殊字符比如<将会被转义为\u003c
• 数组和切片被转换为JSON 里面的数组,[]byte类会被转换为base64编码后的字符串,slice的零值被转换为null
• 结构体会转化为JSON对象,并且只有结构体里边以大写字母开头的可被导出的字段才会被转化输出,而这些可导出的字段会作为JSON对象的字符串索引
• 转化一个map 类型的数据结构时,该数据的类型必须是 map[string]T(T 可以是encoding/json 包支持的任意数据类型)

简单示例

package main

import (
	"fmt"
	"encoding/json"
	"os"
)

func main() {
	type ColorGroup struct {
		ID int
		Name string
		Colors []string
	}
	group := ColorGroup{
		ID: 1,
		Name: "Reds",
		Colors: []string{"black", "blue", "yellow"},
	}
	b,err := json.Marshal(group)
	if err != nil {
		fmt.Println("error: ", err)
	}
	os.Stdout.Write(b)
}

输出: 
{"ID":1,"Name":"Reds","Colors":["black","blue","yellow"]}

解码

把 JSON 转换回对象的方法: 

func Unmarshal(data [] byte, v interface{}) error

这个函数会把传入的 data 作为一个JSON来进行解析,解析后的数据存储在参数 v 中。这个参数 v 也是任意类型的参数(但一定是一个类型的指针),原因是我们在是以此函数进行JSON 解析的时候,这个函数不知道这个传入参数的具体类型,所以它需要接收所有的类型。

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	var jsonBlob = []byte(`[{"Name": "andy","Age": 18},{"Name": "bob","Age": 20}]`)
	type Person struct {
		Name string
		Age uint
	}

	var Persons []Person
	err := json.Unmarshal(jsonBlob, &Persons)
	if err != nil {
		fmt.Println("error: ", err)
	}
	fmt.Printf("%+v", Persons)
}

输出:[{Name:andy Age:18} {Name:bob Age:20}]

Encoders and Decoders

NewDecoder returns a new decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder

A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
        // contains filtered or unexported fields
}

An Encoder writes JSON values to an output stream.
type Encoder struct {
        // contains filtered or unexported fields
}

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 {
		var m Message
		if err := dec.Decode(&m); err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%s: %s\n", m.Name, m.Text)
	}
}

轮流将dec这个包含多个Message变量赋值给m,打印
d: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!

Encode和Marshal的区别 

func Encode is a method on an Encoder, which writes JSON encoded Go types to an output stream (func NewEncoder takes an io.Writer and returns a *Encoder).

Marshal is a function that returns JSON encoding of Go types.

package main

import "encoding/json"
import "fmt"
import "os"

// We'll use these two structs to demonstrate encoding and
// decoding of custom types below.
type Response1 struct {
	Page   int
	Fruits []string
}
type Response2 struct {
	Page   int      `json:"page"`
	Fruits []string `json:"fruits"`
}

func main() {

	// First we'll look at encoding basic data types to
	// JSON strings. Here are some examples for atomic
	// values.
	bolB, _ := json.Marshal(true)
	fmt.Println(string(bolB))

	intB, _ := json.Marshal(1)
	fmt.Println(string(intB))

	fltB, _ := json.Marshal(2.34)
	fmt.Println(string(fltB))

	strB, _ := json.Marshal("gopher")
	fmt.Println(string(strB))

	// And here are some for slices and maps, which encode
	// to JSON arrays and objects as you'd expect.
	slcD := []string{"apple", "peach", "pear"}
	slcB, _ := json.Marshal(slcD)
	fmt.Println(string(slcB))

	mapD := map[string]int{"apple": 5, "lettuce": 7}
	mapB, _ := json.Marshal(mapD)
	fmt.Println(string(mapB))

	// The JSON package can automatically encode your
	// custom data types. It will only include exported
	// fields in the encoded output and will by default
	// use those names as the JSON keys.
	res1D := &Response1{
		Page:   1,
		Fruits: []string{"apple", "peach", "pear"}}
	res1B, _ := json.Marshal(res1D)
	fmt.Println(string(res1B))

	// You can use tags on struct field declarations
	// to customize the encoded JSON key names. Check the
	// definition of `Response2` above to see an example
	// of such tags.
	res2D := &Response2{
		Page:   1,
		Fruits: []string{"apple", "peach", "pear"}}
	res2B, _ := json.Marshal(res2D)
	fmt.Println(string(res2B))

	// Now let's look at decoding JSON data into Go
	// values. Here's an example for a generic data
	// structure.
	byt := []byte(`{"num":6.13,"strs":["a","b"]}`)

	// We need to provide a variable where the JSON
	// package can put the decoded data. This
	// `map[string]interface{}` will hold a map of strings
	// to arbitrary data types.
	var dat map[string]interface{}

	// Here's the actual decoding, and a check for
	// associated errors.
	if err := json.Unmarshal(byt, &dat); err != nil {
		panic(err)
	}
	fmt.Println(dat)

	// In order to use the values in the decoded map,
	// we'll need to cast them to their appropriate type.
	// For example here we cast the value in `num` to
	// the expected `float64` type.
	num := dat["num"].(float64)
	fmt.Println(num)

	// Accessing nested data requires a series of
	// casts.
	strs := dat["strs"].([]interface{})
	str1 := strs[0].(string)
	fmt.Println(str1)

	// We can also decode JSON into custom data types.
	// This has the advantages of adding additional
	// type-safety to our programs and eliminating the
	// need for type assertions when accessing the decoded
	// data.
	str := `{"page": 1, "fruits": ["apple", "peach"]}`
	res := Response2{}
	json.Unmarshal([]byte(str), &res)
	fmt.Println(res)
	fmt.Println(res.Fruits[0])

	// In the examples above we always used bytes and
	// strings as intermediates between the data and
	// JSON representation on standard out. We can also
	// stream JSON encodings directly to `os.Writer`s like
	// `os.Stdout` or even HTTP response bodies.
	enc := json.NewEncoder(os.Stdout)
	d := map[string]int{"apple": 5, "lettuce": 7}
	enc.Encode(d)
}



true
1
2.34
"gopher"
["apple","peach","pear"]
{"apple":5,"lettuce":7}
{"Page":1,"Fruits":["apple","peach","pear"]}
{"page":1,"fruits":["apple","peach","pear"]}
map[num:6.13 strs:[a b]]
6.13
a
{1 [apple peach]}
apple
{"apple":5,"lettuce":7}

net/http的操作中JSON

很显然,json广泛应用在客户端和服务端之间的数据交换。

之前介绍了go中的net/http package 和 encoding/json package,今天介绍一下在net/http的操作中如何使用JSON。

package main

import (
	"encoding/json"
	"fmt"
	"bytes"
	"net/http"
	"io"
	"os"
)

func main() {
	type User struct {
		Id string
		Balance uint64
	}
	u := User{Id:"110", Balance: 8}
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(u)
	fmt.Println(b)

	res,_ := http.Post("https://httpbin.org/post", "application/json; charset=utf-8", b)
	io.Copy(os.Stdout, res.Body)
}

执行结果
{"Id":"110","Balance":8}

{
  "args": {},
  "data": "{\"Id\":\"110\",\"Balance\":8}\n",
  "files": {},
  "form": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Connection": "close",
    "Content-Length": "25",
    "Content-Type": "application/json; charset=utf-8",
    "Host": "httpbin.org",
    "User-Agent": "Go-http-client/1.1"
  },
  "json": {
    "Balance": 8,
    "Id": "110"
  },
  "origin": "103.83.60.170",
  "url": "https://httpbin.org/post"
}

另外一个例子

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {

    url := "https://api.xuebaclass.com/xuebaapi/v1/provinces"

    req, _ := http.NewRequest("GET", url, nil)

    req.Header.Add("accept", "application/json")
    req.Header.Add("content-type", "application/json")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)


    type Province struct {
        Id       int  `json:"id"`
        Province string `json:"province"`
    }
    provinces := make([]Province, 0)
    err := json.Unmarshal([]byte(body), &provinces)
    if err != nil {
        fmt.Println("error:", err)
    }
    fmt.Println(provinces)

}

github上比较活的golang json解析器

下面是一个github上比较活的golang json解析器,也许是全世界最快的。

jsoniter ( json-iterator )是一款快且灵活的 JSON 解析器,同时提供 Java 和 Go 两个版本

Jsoniter 是最快的 JSON 解析器。它最多能比普通的解析器快 10 倍之多,即使在数据绑定的用法下也有同样的性能优势。无耻地献上自己的 跑分

非常易于使用的 api ,允许你使用任何风格或者混搭的方式来解析 JSON 。给你前所未有的灵活性。来看看这些 API 们 是不是真的有那么好用吧

独特的 iterator api 能够直接遍历 JSON ,极致性能! 0 内存分配!这样的 iterator 你绝对没有用过

获取: 

go get github.com/json-iterator/go

简单应用Marshal

var json = jsoniter.ConfigCompatibleWithStandardLibrary
json.Marshal(&data)

package main

import (
    "encoding/json"
    "fmt"
    "os"

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

func main() {
    type ColorGroup struct {
        ID     int
        Name   string
        Colors []string
    }
    group := ColorGroup{
        ID:     1,
        Name:   "Reds",
        Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
    }
    b, err := json.Marshal(group)
    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stdout.Write(b)

    var json_iterator = jsoniter.ConfigCompatibleWithStandardLibrary
    b, err = json_iterator.Marshal(group)
    os.Stdout.Write(b)
}

输出: 
{“ID”:1,”Name”:”Reds”,”Colors”:[“Crimson”,”Red”,”Ruby”,”Maroon”]}
{“ID”:1,”Name”:”Reds”,”Colors”:[“Crimson”,”Red”,”Ruby”,”Maroon”]}

简单应用jsoniter.Get 

一行代码完成解析:
package main

import (
    "fmt"

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

func main() {

    val := []byte(`{"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}`)
    str := jsoniter.Get(val, "Colors", 0).ToString()
    fmt.Println(str)
}

执行结果
Crimson

简单应用NewDecoder

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 {
        fmt.Printf("%+v\n", params)
    }
}

输出:

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]

参考文档:http://blog.csdn.net/wangshubo1989/article/details/78709802

未经允许不得转载:江哥架构师笔记 » go学习:json操作

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址