数据格式操作(json等)

2020-08-04  本文已影响0人  强某某

json

以下分别是切片json互转和map,json互转两种,后者比较麻烦,取值的时候需要进行接口类型断言

package main

import (
    "encoding/json"
    "fmt"
)

type Class struct {
    //结构体转json,成员必须首字母大写,否则转换之后该字段会被忽略
    Subject  string
    Students []string
    Price    float64
    
    //注意:如果结构体字段是大写(一般都是大写)但是提交字段是小写,则需要特殊处理:如下
    // Age int `json:"age"`
}

func main01() {
    cl := Class{"go语言", []string{"呵呵", "哈哈"}, 10}
    // slice, err := json.Marshal(cl)
    // if err != nil {
    //  fmt.Println(err)
    //  return
    // }
    //不转换的话是字符切片,肉眼不可分辨实际内容
    // fmt.Println(string(slice)) //{"Subject":"go语言","Students":["呵呵","哈哈"],"Price":10}

    //格式化输出,一般没啥用处
    slice, err := json.MarshalIndent(cl, "", "    ")
    if err != nil {
        return
    }
    fmt.Println(string(slice))
}

func main02() {
    slice := []byte(`{"Subject":"go语言","Students":["呵呵","哈哈"],"Price":10}`)

    var cl Class
    //本质上传递的是指针,所以也可以new(Class)返回值传递也可
    err := json.Unmarshal(slice, &cl)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(cl)       //{go语言 [呵呵 哈哈] 10}
    fmt.Println(cl.Price) //10  可以这样分开打印
}

func main03() {
    // 创建⼀个保存键值对的映射
    t1 := make(map[string]interface{})
    t1["company"] = "Lianshi"
    t1["subjects "] = []string{"Go", "Web", "Python", "C++"}
    t1["isok"] = true
    t1["price"] = 8980.88
    b, err := json.Marshal(t1)
    //json.MarshalIndent(t1, "", " ")
    if err != nil {
        fmt.Println("json err:", err)
    }
    fmt.Println(string(b)) //{"company":"Lianshi","isok":true,"price":8980.88,"subjects ":["Go","Web","Python","C++"]}
}

func main() {
    b := []byte(`{
        "company": "Lianshi",
        "subjects": [
         "Go",
         "Web",
         "Python",
         "C++"
        ],
        "isok": true,
        "price": 8980.88
        }`)
    //默认返回值类型为interface类型 以map类型进⾏格式存储
    //可以理解为:json的key为map的key json的value为map的value
    //格式:map[string]interface{}
    // var t interface{}
    // err := json.Unmarshal(b, &t)
    // if err != nil {
    //  fmt.Println("json err:", err)
    // }
    // fmt.Println(t)

    //使⽤断⾔判断类型
    // m := t.(map[string]interface{})

    //或者上面用下面几行替换
    m := make(map[string]interface{})
    err := json.Unmarshal(b, &m)
    if err != nil {
        fmt.Println("json err:", err)
    }

    for k, v := range m {
        switch val := v.(type) {
        case string:
            fmt.Println(k, "is string", val)
        case int:
            fmt.Println(k, "is int", val)
        case float64:
            fmt.Println(k, "is float64", val)
        case bool:
            fmt.Println(k, "is bool", val)
        case []interface{}:
            fmt.Println(k, "is an array:")
            for i, u := range val {
                fmt.Println(i, u)
            }
        default:
            fmt.Println(k, "is of a type I don't know how to handle")
        }
    }
}

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>
package main

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

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

type Server struct {
    ServerName string `xml:"serverName"`
    ServerIP   string `xml:"serverIP"`
}

func main() {
    data, err := ioutil.ReadFile("./config.xml")
    if err != nil {
        fmt.Printf("read config.xml failed, err:%v\n", err)
        return
    }
    var servers Servers
    err = xml.Unmarshal(data, &servers)
    if err != nil {
        fmt.Printf("unmarshal failed, err:%v\n", err)
        return
    }
    fmt.Printf("xml: %#v\n", servers)
}

msgpack数据格式

二进制形式的json协议

  1. 性能更快
  2. 更省空间
  3. 安装 go get github.com/vmihailenco/msgpack
  4. 官网:https://msgpack.org/
  5. 有通用js库可以解析,顾可以再前端后台node使用
package main

import (
    "fmt"
    "io/ioutil"
    "math/rand"

    "github.com/vmihailenco/msgpack"
)

type Person struct {
    Name string
    Age  int
    Sex  string
}

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:  "Man",
        }

        persons = append(persons, p)
    }

    data, err := msgpack.Marshal(persons)
    if err != nil {
        fmt.Printf("=marshal 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
}

func readJson(filename string) (err error) {
    var persons []*Person
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return
    }

    err = msgpack.Unmarshal(data, &persons)
    if err != nil {
        return
    }

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

func main() {
    filename := "C:/tmp/person.dat"
    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
    }
}

Protobuf

开发流程

IDL编写

1.jpg
enum EnumAllowingAlias { 
UNKNOWN = 0; 
STARTED = 1; 
RUNNING = 2; 
}
message Person {
//后面的数字表示标识号,就是序号,是给proto内部使用的
int32 id = 1;
string name = 2;
//repeated表示可重复
//可以有多个手机
repeated Phone phones = 3;
}

Golang应用

2.jpg
//指定版本
//注意proto3与proto2的写法有些不同
syntax = "proto3";
 
//包名,通过protoc生成时go文件时
package address;
 
//手机类型
//枚举类型第一个字段必须为0
enum PhoneType {
    HOME = 0;
    WORK = 1;
}
 
//手机
message Phone {
    PhoneType type = 1;
    string number = 2;
}
 
//人
message Person {
    //后面的数字表示标识号
    int32 id = 1;
    string name = 2;
    //repeated表示可重复
    //可以有多个手机
    repeated Phone phones = 3;
}
 
//联系簿
message ContactBook {
    repeated Person persons = 1;
}
package main

import (
    "fmt"
    "io/ioutil"

    "github.com/golang/protobuf/proto"
    //此处引入的就是生成的proto对应go文件
    "github.com/pingguoxueyuan/gostudy/listen24/protobuf/address"
)

func writeProto(filename string) (err error) {
    var contactBook address.ContactBook
    for i := 0; i < 64; i++ {
        p := &address.Person{
            Id:   int32(i),
            //Sprintf返回字符串
            Name: fmt.Sprintf("陈%d", i),
        }

        phone := &address.Phone{
            Type:   address.PhoneType_HOME,
            Number: "15910624165",
        }

        p.Phones = append(p.Phones, phone)
        contactBook.Persons = append(contactBook.Persons, p)
    }

    data, err := proto.Marshal(&contactBook)
    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
}

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

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

func main() {
    filename := "c:/tmp/contactbook.dat"
    err := writeProto(filename)
    if err != nil {
        fmt.Printf("write proto failed, err:%v\n", err)
        return
    }
    err = readProto(filename)
    if err != nil {
        fmt.Printf("read proto failed, err:%v\n", err)
        return
    }
}
上一篇下一篇

猜你喜欢

热点阅读