Golang中 json.Decoder vs json.Unmarshal

json的反序列化方式有两种:

  1. Use json.Unmarshal passing the entire response string
    // func Unmarshal(data []byte, v interface{}) error
    data, err := ioutil.ReadAll(resp.Body)
    if err == nil && data != nil {
        err = json.Unmarshal(data, value)
    }
    
  2. using json.NewDecoder.Decode
    // func NewDecoder(r io.Reader) *Decoder
    // func (dec *Decoder) Decode(v interface{}) error
    err = json.NewDecoder(resp.Body).Decode(value)
    

这两种方法看似差不多,但有不同的应用场景

  • Use json.Decoder if your data is coming from an io.Reader stream, or you need to decode multiple values from a stream of data.

    For the case of reading from an HTTP request, I’d pick json.Decoder since you’re obviously reading from a stream.

  • Use json.Unmarshal if you already have the JSON data in memory.

例子

从文件中读入一个巨大的json数组用json.Decoder

json.Decoder会一个一个元素进行加载,不会把整个json数组读到内存里面

package main

import (
	"encoding/json"
	"fmt"
	"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))

	// read open bracket
	t, err := dec.Token()
	if err != nil {
		log.Fatal(err)
	}
	// t的类型是json.Delim
	fmt.Printf("%T: %v\n", t, t)

	// while the array contains values
	for dec.More() {
		var m Message
		// decode an array value (Message)
		err := dec.Decode(&m)
		if err != nil {
			log.Fatal(err)
		}

		fmt.Printf("%v: %v\n", m.Name, m.Text)
	}

	// read closing bracket
	t, err = dec.Token()
	if err != nil {
		log.Fatal(err)
	}
	// t的类型是json.Delim
	fmt.Printf("%T: %v\n", t, t)

}

结果:

json.Delim: [
Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!
json.Delim: ]

从文件中读入json流用json.Decoder

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)
	}
}

结果:

Ed: Knock knock.
Sam: Who's there?
Ed: Go fmt.
Sam: Go fmt who?
Ed: Go fmt yourself!

本来就以[]byte存在于内存中的用json.Unmarshal

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	var jsonBlob = []byte(`[
	{"Name": "Platypus", "Order": "Monotremata"},
	{"Name": "Quoll",    "Order": "Dasyuromorphia"}
]`)
	type Animal struct {
		Name  string
		Order string
	}
	var animals []Animal
	err := json.Unmarshal(jsonBlob, &animals)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v", animals)
}

结果:

[{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]

直接读入json数组的两种方式

data.json

[
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1001",
	"type" : "rss"
},
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1008",
	"type" : "rss"
},
{
	"site" : "npr",
	"link" : "http://www.npr.org/rss/rss.php?id=1006",
	"type" : "rss"
}
]

1. 得到数组元素的地址

[]*Feed

package main

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

const dataFile = "data.json"

type Feed struct {
	Name string `json:"site"`
	URI  string `json:"link"`
	Type string `json:"type"`
}

func main() {
	//hello.Hello()
	file, err := os.Open(dataFile)
	if err != nil {
		os.Exit(1)
	}
	defer file.Close()

	var feeds []*Feed
	err = json.NewDecoder(file).Decode(&feeds)

	fmt.Printf("%T | %v\n", feeds, feeds)

	for i := range feeds {
		fmt.Println(*feeds[i])
	}

}

结果:

[]*main.Feed | [0xc0420861e0 0xc0420862a0 0xc0420862d0]
{npr http://www.npr.org/rss/rss.php?id=1001 rss}
{npr http://www.npr.org/rss/rss.php?id=1008 rss}
{npr http://www.npr.org/rss/rss.php?id=1006 rss}

2. 得到数组元素的拷贝

[]Feed

package main

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

const dataFile = "data.json"

type Feed struct {
	Name string `json:"site"`
	URI  string `json:"link"`
	Type string `json:"type"`
}

func main() {
	//hello.Hello()
	file, err := os.Open(dataFile)
	if err != nil {
		os.Exit(1)
	}
	defer file.Close()

	var feeds []Feed
	err = json.NewDecoder(file).Decode(&feeds)

	fmt.Printf("%T | %v\n", feeds, feeds)

	// for i := range feeds {
	// 	fmt.Println(*feeds[i])
	// }

}

结果:

[]main.Feed | [{npr http://www.npr.org/rss/rss.php?id=1001 rss} {npr http://www.npr.org/rss/rss.php?id=1008 rss} {npr http://www.npr.org/rss/rss.php?id=1006 rss}]

你可能感兴趣的:(go语言,2018)