最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言中的數(shù)據(jù)格式(json、xml?、msgpack、protobuf)使用總結(jié)

 更新時(shí)間:2022年07月25日 09:09:28   作者:奮斗的大橙子  
在分布式的系統(tǒng)中,因?yàn)樯婕暗綌?shù)據(jù)的傳輸,所以一定會(huì)進(jìn)行數(shù)據(jù)的交換,此時(shí)就要定義數(shù)據(jù)交換的格式,例如二進(jìn)制、Json、Xml等等。本文總結(jié)了Go語言中的數(shù)據(jù)格式,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在分布式的系統(tǒng)中,因?yàn)樯婕暗綌?shù)據(jù)的傳輸,所以一定會(huì)進(jìn)行數(shù)據(jù)的交換,此時(shí)就要定義數(shù)據(jù)交換的格式,例如二進(jìn)制、Json、Xml等等。本篇文章就是總結(jié)一下常用的幾種數(shù)據(jù)格式。

一、Json格式

如果想使用Json數(shù)據(jù)格式,可以借助于encoding/json這個(gè)包。

利用json包里的 json.Marshal(xxx) 和 json.Unmarshal(data, &xxx) 進(jìn)行序列化和反序列化。

下面舉個(gè)例子:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "math/rand"
)

type Student struct {
    Name string
    Age  int
    Sex  string
}

//寫入json數(shù)據(jù)
func writeJson(filename string) (err error) {
    var students []*Student
    //隨機(jī)生成10個(gè)學(xué)生數(shù)據(jù)
    for i := 0; i < 10; i++ {
        p := &Student{
            Name: fmt.Sprintf("name%d", i),
            Age:  rand.Intn(100),
            Sex:  "Man",
        }

        students = append(students, p)
    }

    //執(zhí)行序列化操作
    data, err := json.Marshal(students)
    if err != nil {
        fmt.Printf("=marshal failed, err:%v\n", err)
        return
    }

    //將數(shù)據(jù)寫到一個(gè)文件當(dāng)中
    err = ioutil.WriteFile(filename, data, 0755)
    if err != nil {
        fmt.Printf("write file failed, err:%v\n", err)
        return
    }

    return
}

//讀取json數(shù)據(jù)
func readJson(filename string) (err error) {
    var students []*Student
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return
    }

    err = json.Unmarshal(data, &students)
    if err != nil {
        return
    }

    for _, v := range students {
        fmt.Printf("%#v\n", v)
    }
    return
}

執(zhí)行:

func main() {
    filename := "C:/tmp/Students.txt"
    err := writeJson(filename)
    if err != nil {
        fmt.Printf("write json failed, err:%v\n", err)
        return
    }

    err = readJson(filename)
    if err != nil {
        fmt.Printf("read json failed, err:%v\n", err)
        return
    }
}

執(zhí)行結(jié)果:

  • 1.可以看到在C:/tmp/下面生成了一個(gè)Students.txt文件,打開里面存放是剛剛隨機(jī)生成的10個(gè)學(xué)生數(shù)據(jù)
  • 2.執(zhí)行結(jié)果可以看到控制臺(tái)打?。?/li>

二、Xml格式

Xml格式也是我們常用的數(shù)據(jù)格式,同樣要使用Xml格式,可以使用encoding/xml這個(gè)包。

像上面json一樣,同樣存在 xml.Marshal(xxx) 和 xml.Unmarshal(data, &xxx) 兩個(gè)方法。此外還有方法xml.MarshalIndent(xxx) 可以格式化xml

先熟悉一下XML對(duì)應(yīng) 標(biāo)簽怎么寫:

  • - XMLName字段,如上所述,會(huì)省略
  • - 具有標(biāo)簽"-"的字段會(huì)省略
  • - 具有標(biāo)簽"name,attr"的字段會(huì)成為該XML元素的名為name的屬性
  • - 具有標(biāo)簽",attr"的字段會(huì)成為該XML元素的名為字段名的屬性
  • - 具有標(biāo)簽",chardata"的字段會(huì)作為字符數(shù)據(jù)寫入,而非XML元素
  • - 具有標(biāo)簽",innerxml"的字段會(huì)原樣寫入,而不會(huì)經(jīng)過正常的序列化過程
  • - 具有標(biāo)簽",comment"的字段作為XML注釋寫入,而不經(jīng)過正常的序列化過程,該字段內(nèi)不能有"--"字符串
  • - 標(biāo)簽中包含"omitempty"選項(xiàng)的字段如果為空值會(huì)省略
    空值為false、0、nil指針、nil接口、長(zhǎng)度為0的數(shù)組、切片、映射
  • - 匿名字段(其標(biāo)簽無效)會(huì)被處理為其字段是外層結(jié)構(gòu)體的字段
  • - 如果一個(gè)字段的標(biāo)簽為"a>b>c",則元素c將會(huì)嵌套進(jìn)其上層元素a和b中。如果該字段相鄰的字段標(biāo)簽指定了同樣的上層元素,則會(huì)放在同一個(gè)XML元素里。
  • - 如果一個(gè)字段的標(biāo)簽為"a>b>c",則元素c將會(huì)嵌套進(jìn)其上層元素a和b中。如果該字段相鄰的字段標(biāo)簽指定了同樣的上層元素,則會(huì)放在同一個(gè)XML元素里。

下面舉個(gè)例子:

例如我想創(chuàng)建一個(gè)如下的xml數(shù)據(jù):

<Servers version="2.0">
    <server>
        <serverName>Server0</serverName>
        <serverIP>192.168.1.0</serverIP>
    </server>
    <server>
        <serverName>Server1</serverName>
        <serverIP>192.168.1.1</serverIP>
    </server>
</Servers>

我就可以創(chuàng)建下面這樣的結(jié)構(gòu)體:

//最外層的xml
type Servers struct {
    XMLName xml.Name  `xml:"Servers"`
    Version string    `xml:"version,attr"`
    Servers []*Server `xml:"server"`
}

//具體的server
type Server struct {
    ServerName string `xml:"serverName"`
    ServerIP   string `xml:"serverIP"`
}

寫文件方法:

func writeXml(fileName string) (err error) {
    //創(chuàng)建一個(gè)*Server類型的數(shù)組
    var serverList []*Server
    for i := 0; i < 2; i++ {
        s := &Server{
            ServerName: fmt.Sprintf("Server%d", i),
            ServerIP:   fmt.Sprintf("192.168.1.%d", i),
        }
        serverList = append(serverList, s)
    }

    var myServers *Servers = &Servers{
        Version: "2.0",
        Servers: serverList,
    }

    //執(zhí)行序列化操作
    data, err := xml.MarshalIndent(myServers, "", "    ")
    if err != nil {
        fmt.Printf("=marshal failed, err:%v\n", err)
        return
    }

    //將數(shù)據(jù)寫到一個(gè)文件當(dāng)中
    err = ioutil.WriteFile(fileName, data, 0755)
    if err != nil {
        fmt.Printf("write file failed, err:%v\n", err)
        return
    }

    return
}

如上代碼,使用了MarshalIndent方法,第一個(gè)參數(shù)是需要序列化的數(shù)據(jù),第二參數(shù)是前綴,第三個(gè)是縮進(jìn)的字符串(這里是四個(gè)空格),然后在main方法中調(diào)用一下即可(代碼略)。

這里主要想說明一下結(jié)構(gòu)體里面的標(biāo)簽:

XmlName可以省略不寫,不寫的話最外層就是用的結(jié)構(gòu)體的名稱,例如第一個(gè)結(jié)構(gòu)體是Servers,那么xml最外層的節(jié)點(diǎn)名稱就是Servers。

讀的話,使用 xml.Unmarshal(data, &xxx) 就可以實(shí)現(xiàn)了。

func readXml(fileName string) (err error) {
    var myServers *Servers
    data, err := ioutil.ReadFile(fileName)
    if err != nil {
        return
    }

    err = xml.Unmarshal(data, &myServers)
    if err != nil {
        return
    }

    fmt.Printf("XMLNAME = %v\n", myServers.XMLName)
    fmt.Printf("Version = %v\n", myServers.Version)
    for _, v := range myServers.Servers {
        fmt.Printf("%v\n", v)
    }
    return
}

三、msgPack格式

上面兩種Json和Xml格式,都是文本格式的數(shù)據(jù),好處在于能夠方便的閱讀。但是問題在于占用空間比較大。所以又出現(xiàn)了MsgPack這種格式,它是在json基礎(chǔ)上轉(zhuǎn)換為二進(jìn)制進(jìn)行傳輸?shù)?。?duì)應(yīng)關(guān)系像下面這個(gè)圖:

MsgPack并沒有官方的包,我們需要使用一個(gè)第三方的包,項(xiàng)目地址:https://github.com/vmihailenco/msgpack

實(shí)現(xiàn)比較簡(jiǎn)單,將 json.Marshal 和 json.Unmarshal 中的【 json】替換為【 maspack】即可,下面是對(duì)上面代碼的改造,創(chuàng)建了10000個(gè)學(xué)生的數(shù)據(jù)。

四、protobuf格式

protobuf是Google公司開發(fā)出的一種數(shù)據(jù)格式。官方文檔地址:https://developers.google.cn/protocol-buffers/ 。

簡(jiǎn)單講它使用了IDL語言作為中間語言來串聯(lián)不同的編程語言。不同的語言可以根據(jù)生成的IDL中間語言,生成自己的語言。

這樣做有什么好處? 舉個(gè)例子:當(dāng)我們?cè)趨f(xié)作開發(fā)的時(shí)候,A部門使用的是Go語言、B部分使用的是Java語言,C部門使用的是C#語言,當(dāng)他們之間進(jìn)行數(shù)據(jù)交換的時(shí)候,都要各自維護(hù)自己的結(jié)構(gòu)體,才能進(jìn)行數(shù)據(jù)的

序列化和反序列化,使用protobuf的好處就是只需要一個(gè)IDL描述,然后生成不同的語言的結(jié)構(gòu),這樣維護(hù)一份就可以了。

同時(shí) prototbuf的性能也很好,這也是它的一個(gè)優(yōu)勢(shì)。IDL語言使用的變長(zhǎng)編碼(根據(jù)整數(shù)的范圍 0-255 那么這個(gè)數(shù)字就占用1個(gè)字節(jié) ,如果使用定長(zhǎng)編碼的話 一個(gè)整數(shù)可能就是 4個(gè)字節(jié))所以它的空間利用率是很好的。

那開發(fā)流程是怎樣的?

  • A. IDL編寫
  • B. 生成只定語言的代碼
  • C. 序列化和反序列化

如何在Go中應(yīng)用prototbuf

A.安裝protoc編譯器

解壓后拷貝到GOPATH/bin目錄下, 下載地址:https://github.com/google/protobuf/releases

然后把bin下面的protoc.exe 這個(gè)放到GoPath下的bin中,打開cmd,輸入protoc,應(yīng)該會(huì)出現(xiàn)如下內(nèi)容:

如果不存在,可以將Gopath的bin加入到系統(tǒng)的環(huán)境變量path當(dāng)中。

B.安裝生成Go語言的插件

執(zhí)行命令:

go get -u github.com/golang/protobuf/protoc-gen-go

C. 創(chuàng)建一個(gè)簡(jiǎn)單的proto文件

//指定版本
//注意proto3與proto2的寫法有些不同
syntax = "proto3";

//包名,通過protoc生成時(shí)go文件時(shí)
package school;

//性別
//枚舉類型第一個(gè)字段必須為0
enum Sex {
    male = 0;
    female = 1;
    other =2;
}

//學(xué)生
message Student {
    Sex sex = 1;
    string Name = 2;
    int32 Age =3;
}

//班級(jí)
message Class{
    repeated Student Students =1;
    string Name; 
}

message 就可以理解成類, repeated可以理解成數(shù)組。

D.利用之前下載好的protoc.exe 生成一個(gè)Go的代碼。

第一個(gè)【.】代表當(dāng)前輸出的目錄,后面*.proto則是 proto文件的路徑

protoc--go_out=.  *.proto

protoc --go_out=.\school\ .\school.proto

執(zhí)行之后會(huì)生成如下的文件,這個(gè)go文件就可以直接使用了。

E. 使用生成的Go文件

①使用 proto.Marshal() 執(zhí)行序列化

func writeProto(filename string) (err error) {
    //創(chuàng)建學(xué)生信息
    var students []*school.Student
    for i := 0; i < 30; i++ {

        var sex = (school.Sex)(i % 3)
        student := &school.Student{
            Name: fmt.Sprintf("Student_%d", i),
            Age:  15,
            Sex:  sex,
        }

        students = append(students, student)
    }

    //創(chuàng)建班級(jí)信息
    var myClass school.Class
    myClass.Name = "我的班級(jí)"
    myClass.Students = students

    data, err := proto.Marshal(&myClass)
    if err != nil {
        fmt.Printf("marshal proto buf failed, err:%v\n", err)
        return
    }

    err = ioutil.WriteFile(filename, data, 0755)
    if err != nil {
        fmt.Printf("write file failed, err:%v\n", err)
        return
    }
    return
}

②使用proto.Unmarshal(data, &mySchool)執(zhí)行反序列化

func readProto(filename string) (err error) {
    var mySchool school.Class
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return
    }
    err = proto.Unmarshal(data, &mySchool)
    if err != nil {
        return
    }

    fmt.Printf("proto:%v\n", mySchool)
    return
}

Q&A

如果在使用protobuf生成的Go文件,出現(xiàn)了如下的異常:

undefined: proto.ProtoPackageIsVersion3

這個(gè)時(shí)候可能是由于上面兩步下載的protoc.exe 和 protobuf 的版本不一致導(dǎo)致的。

  • 1. 可以清空下gopath下的 github.com\golang\protobuf 然后重新下載,并在github.com\golang\protobuf\protoc-gen-go 執(zhí)行 go install 命令。
  • 2. 檢查一下是不是使用了 godep 等包管理工具,里面引用的版本和protoc.exe 不一致造成的

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • Go日志之日志庫講解

    Go日志之日志庫講解

    本文介紹了Go語言中最優(yōu)秀的日志庫,包括Zap、log/slog、Logrus和Zerolog,它們都提供了結(jié)構(gòu)化日志記錄、自定義日志級(jí)別、輸出目標(biāo)等特性,感興趣的可以了解一下
    2026-04-04
  • Go語言基礎(chǔ)結(jié)構(gòu)體用法及示例詳解

    Go語言基礎(chǔ)結(jié)構(gòu)體用法及示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)結(jié)構(gòu)體的用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • GoLang中panic與recover函數(shù)以及defer語句超詳細(xì)講解

    GoLang中panic與recover函數(shù)以及defer語句超詳細(xì)講解

    這篇文章主要介紹了GoLang的panic、recover函數(shù),以及defer語句,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • 使用Go語言玩轉(zhuǎn) RESTful API 服務(wù)

    使用Go語言玩轉(zhuǎn) RESTful API 服務(wù)

    RESTful API是一種基于HTTP協(xié)議的API設(shè)計(jì)風(fēng)格,遵循REST架構(gòu)風(fēng)格,這篇文章主要為大家介紹了如何通過Go語言構(gòu)建RESTful API服務(wù),有需要的可以了解下
    2025-02-02
  • golang實(shí)踐-第三方包為私有庫的配置方案

    golang實(shí)踐-第三方包為私有庫的配置方案

    這篇文章主要介紹了golang實(shí)踐-第三方包為私有庫的配置方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • GO字符串練習(xí)題實(shí)例代碼

    GO字符串練習(xí)題實(shí)例代碼

    字符串在Go語言中是一個(gè)不可變的字節(jié)序列,通常用來表示文本,這篇文章主要介紹了GO字符串練習(xí)題的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2026-03-03
  • 解析Golang中引用類型是否進(jìn)行引用傳遞

    解析Golang中引用類型是否進(jìn)行引用傳遞

    這篇文章主要為大家介紹了Golang中引用類型是否進(jìn)行引用傳遞剖析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 基于Go語言實(shí)現(xiàn)文件上傳服務(wù)的示例代碼

    基于Go語言實(shí)現(xiàn)文件上傳服務(wù)的示例代碼

    在 Web 開發(fā)中,文件上傳 是常見需求,例如頭像上傳、文檔存儲(chǔ)、圖片分享等功能,Go 語言的標(biāo)準(zhǔn)庫 net/http 已經(jīng)內(nèi)置了對(duì) multipart/form-data 類型的支持,能讓我們輕松構(gòu)建一個(gè)文件上傳服務(wù),本文將帶你實(shí)現(xiàn)一個(gè)可運(yùn)行的文件上傳接口,需要的朋友可以參考下
    2025-08-08
  • go語言使用gorilla/websocket實(shí)現(xiàn)websocket

    go語言使用gorilla/websocket實(shí)現(xiàn)websocket

    Gorilla WebSocket 是一個(gè)用于 Go 語言的 WebSocket 協(xié)議實(shí)現(xiàn),而且是一個(gè)優(yōu)秀的組件庫,能快速實(shí)現(xiàn)websocket協(xié)議,下面就跟隨小編一起來看看它的具體使用吧
    2025-04-04
  • 一文帶你全面掌握Go語言中的正則表達(dá)式

    一文帶你全面掌握Go語言中的正則表達(dá)式

    正則表達(dá)式是一種強(qiáng)大的模式匹配工具,能夠在文本中進(jìn)行靈活的搜索和替換操作,本文將介紹?Golang?中的正則表達(dá)式語法,包括常用的匹配符號(hào)、模式修飾符以及示例應(yīng)用,希望對(duì)大家有所幫助
    2023-05-05

最新評(píng)論

辽阳县| 万全县| 屏边| 泾阳县| 交城县| 黑龙江省| 玉门市| 武安市| 甘德县| 平罗县| 敦化市| 山阴县| 新龙县| 塔河县| 丹东市| 志丹县| 庐江县| 米脂县| 浙江省| 台东市| 淅川县| 苏尼特右旗| 岐山县| 方正县| 紫金县| 花莲县| 九台市| 浠水县| 噶尔县| 金坛市| 卢氏县| 泸西县| 时尚| 乌兰浩特市| 遵义县| 盐山县| 灯塔市| 新兴县| 界首市| 张家界市| 延川县|