数据格式操作(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协议
- 性能更快
- 更省空间
- 安装 go get github.com/vmihailenco/msgpack
- 官网:https://msgpack.org/
- 有通用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
- google推出的数据交换格式
- 二进制
- 基于代码自动生成
开发流程
- IDL编写
- 生成指定语言的代码
- 序列化和反序列化
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应用
- 安装protoc编译器,解压后拷贝到GOPATH/bin目录下(就是项目目录bin下)
- https://github.com/google/protobuf/releases
- 安装golang代码插件, go get -u github.com/golang/protobuf/protoc-gen-go
- 生成代码, protoc --go_out=. *.proto
- protoc --go_out=./address .\person.proto
- 通过当前目录下的person.proto文件生成go代码到address目录(必须存在)下,默认生成文件名是person.pb.go
- 注意:如果protoc --go_out没有配置环境变量需要配置下
//指定版本
//注意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
}
}