Golang 常見數據格式處理


數據格式介紹

  • 數據格式是系統中數據交互不可缺少的內容
  • 這里主要介紹JSONXMLMSGPack

JSON

  • json 是完全獨立於語言的文本格式,是 k-v 的形式 name:zs
  • 應用場景:前后端交互,系統間數據交互
  • json 使用 go 語言內置的 encoding/json 標准庫

編碼 json 使用 json.Marshal()函數可以對一組數據進行 JSON 格式的編碼

生成 json 格式

通過結構體生成 JSON

需要格式化的結構體中的字段必須是一個外部可調用的字段(首寫字母大寫),否則再 json 包中無法識別則讀取不到

輸出的 jsonkey是字段名稱

package main

import (
	"encoding/json"
	"fmt"
)


type Person struct {
	Name string
	Age int
}

func main() {

	p := &Person{"zs", 18}

	// 生成json
	b, err := json.Marshal(p)
	if err != nil {
		fmt.Println("json 序列化失敗", err)
		return
	}

	fmt.Println(string(b))

	// 格式化輸出
	b, err = json.MarshalIndent(p, "", "  ")
	if err != nil {
		fmt.Println("json 格式化失敗", err)
		return
	}
	fmt.Println(string(b))
}

struct tag

上面我們可以直接將結構體序列化為一個 json,但是發現 json 的key是字段名稱,不是我們想要的key名稱,這個怎么辦呢?這里就需要用到 go 中的tag特性了,我們再字段后添加一個jsontag 指定想要輸出的key名稱即可。

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age int `json:"age"`
}

func main() {

	p := &Person{"zs", 18}

	// 生成json
	b, err := json.Marshal(p)
	if err != nil {
		fmt.Println("json 序列化失敗", err)
		return
	}
	fmt.Println(string(b))
}

通過 map 生成 json

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	m := make(map[string]interface{})
	m["name"] = "li"
	m["age"] = 18
	m["sex"] = "男"

	b,err := json.Marshal(m)
	if err != nil {
		fmt.Println("json 序列化失敗", err)
		return
	}
	fmt.Println(string(b))
}

解析 json 格式

解碼 json 使用json.Unmarshal()函數可以對一組數據進行 JSON 格式的解碼

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

解析到結構體

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	//Age int	`json:"int"`
	Age int	`json:"int,string"`
	Sex string `json:"sex"`
}

func main() {
	//jsonData := []byte(`{"name":"zs","age":18,"sex":"男"}`)
	jsonData := []byte(`{"name":"zs","age":"18"","sex":"男"}`)
	var p Person

	err := json.Unmarshal(jsonData, &p)
	if err != nil {
		fmt.Println("反序列化失敗", err)
		return
	}
	fmt.Println(p)
}

解析到 interface

package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age int	`json:"int"`
	Sex string `json:"sex"`
}

func main() {
	jsonData := []byte(`{"name":"zs","age":18,"sex":"男"}`)
	var i interface{}

	err := json.Unmarshal(jsonData, &i)
	if err != nil {
		fmt.Println("反序列化失敗", err)
		return
	}
	fmt.Println(i)
}

XML

  • xml 是可擴展標記語言,包含聲明、根標簽、子元素和屬性
  • 應用場景:配置文件以及 webService

xml 文件示例

<?xml version="1.0" encoding="UTF-8" ?>
<servers version="1">
    <server>
        <serverName>Shanghai_VPN</serverName>
        <serverIP>127.0.0.1</serverIP>
    </server>
    <server>
        <serverName>Beijing_VPN</serverName>
        <serverIP>127.0.0.2</serverIP>
    </server>
</servers>

解析和讀取規則

golang 對 xml 的解析和讀取是通過 stuct 和 refect 實現的,對於 struct 中的 tag 以什么方式對應到 xml 的元素上,golang 的文檔中做了如下描述:

  1. 如果 struct 的一個字段是 string 或者[]byte 類型且它的 tag 含有",innerxml",Unmarshal 將會將此字段所對應的元素內所有內嵌的原始 xml 累加到此字段上
  2. 如果 struct 中有一個叫做 XMLName,且類型為 xml.Name 字段,那么在解析的時候就會保存這個 element 的名字到該字段
  3. 如果某個 struct 字段的 tag 定義中含有 XML 結構中 element 的名稱,那么解析的時候就會把相應的 element 值賦值給該字段
  4. 如果某個 struct 字段的 tag 定義了中含有",attr",那么解析的時候就會將該結構所對應的 element 的與字段同名的屬性的值賦值給該字段
  5. 如果某個 struct 字段的 tag 定義 型如"a>b>c",則解析的時候,會將 xml 結構 a 下面的 b 下面的 c 元素的值賦值給該字段
  6. 如果某個 struct 字段的 tag 定義了"-",那么不會為該字段解析匹配任何 xml 數據
  7. 如果 struct 字段后面的 tag 定義了",any",如果他的子元素在不滿足其他的規則的時候就會匹配到這個字段
  8. 如果某個 XML 元素包含一條或者多條注釋,那么這些注釋將被累加到第一個 tag 含有",comments"的字段上,這個字段的類型可能是[]byte 或 string,如果沒有這樣的字段存在,那么注釋將會被拋棄

讀取 xml

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
)

// 抽取xml結構
type Server struct {
	ServerName string `xml:"serverName"`
	ServerIP   string `xml:"serverIP"`
}

type Servers struct {
	XMLName xml.Name `xml:"servers"`
	Version xml.Attr `xml:"version,attr"`
	Servers []Server `xml:"server"`
}

func main() {
	data, err := ioutil.ReadFile("./test.xml")
	if err != nil {
		fmt.Println(err)
		return
	}

	var servers Servers
	err = xml.Unmarshal(data, &servers)
	if err != nil {
		fmt.Println(err)
		return
	}
	//fmt.Printf("%#v", servers)
	fmt.Printf("%v", servers)
}

生成 xml

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
)

// 抽取xml結構
type Server struct {
	ServerName string `xml:"serverName"`
	ServerIP   string `xml:"serverIP"`
}

type Servers struct {
	XMLName xml.Name `xml:"servers"`
	Version xml.Attr `xml:"version,attr"`
	Servers []Server `xml:"server"`
}

func main() {
	data, err := ioutil.ReadFile("./test.xml")
	if err != nil {
		println(err)
		return
	}

	var servers Servers
	err = xml.Unmarshal(data, &servers)
	if err != nil {
		println(err)
		return
	}
	//fmt.Printf("%#v", servers)
	fmt.Printf("%v\n", servers)

	// 將讀取到的xml數據,通過xml.Marshal()方法再轉換為xml格式
	d, err := xml.Marshal(&servers)
	if err != nil {
		println(err)
		return
	}
	fmt.Println(string(d))
}

MSGPack

  • MSGPack 是二進制的 json,性能更快,更省空間
  • 需要安裝第三方包:go get -u github.com/vmihailenco/msgpack
package main

import (
	"fmt"
	"github.com/vmihailenco/msgpack"
	"io/ioutil"
	"math/rand"
)

type Person struct {
	Name string
	Age  int
	Sex  string
}

// 寫入json
func writeJson(filename string) (err error) {
	var persons []*Person

	// 制作數據
	for i := 0; i < 10; i++ {
		p := &Person{
			Name: fmt.Sprintf("name%d", i),
			Age:  rand.Intn(100),
			Sex:  "male",
		}
		persons = append(persons, p)
	}

	// 二進制json格式化
	data, err := msgpack.Marshal(persons)
	if err != nil {
		return
	}

	err = ioutil.WriteFile(filename, data, 0666)
	if err != nil {
		return
	}

	return
}

// 讀取二進制json數據
func readJson(filename string) (persons []*Person, err error) {

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}

	// 反序列化
	err = msgpack.Unmarshal(data, &persons)
	if err != nil {
		return
	}

	return persons, err
}

func main() {
	//err := writeJson("./persons.json")
	//if err != nil {
	//	fmt.Println(err)
	//	return
	//}

	persons, err := readJson("./persons.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, v := range persons {
		fmt.Printf("%#v", v)
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM