Golang处理JSON(一) 序列化

程序猿编码 · · 3156 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

前言

JSON 是目前最为流行的序列化手段,Go语言对于这些标准格式的编码和解码都有良好的支持,在Go语言中,encoding/json标准包处理json数据的序列化与反序列化问题。下面主要讲解序列化。

什么是序列化

序列化是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。通过从存储区中读取对象的状态,重新创建该对象,则为反序列化。

各种类型的值

JSON是对JavaScript中各种类型的值——字符串、数字、布尔值和对象——Unicode本文编码。它可以用有效可读的方式表示基础数据类型和数组、slice、结构体和map等聚合数据类型。对于json的数据类型,go也会有对象的结构所匹配。大致对应关系如下:

在解析 json 格式数据时,若以 interface{} 接收数据,需要按照以上规则进行解析。

序列化 Marshal()

序列化源码放在:


json.Marshal()

// Marshal returns the JSON encoding of v.
//
// Marshal traverses the value v recursively.
// If an encountered value implements the Marshaler interface
// and is not a nil pointer, Marshal calls its MarshalJSON method
// to produce JSON. If no MarshalJSON method is present but the
// value implements encoding.TextMarshaler instead, Marshal calls
// its MarshalText method and encodes the result as a JSON string.
// The nil pointer exception is not strictly necessary
// but mimics a similar, necessary exception in the behavior of
// UnmarshalJSON.
//
// Otherwise, Marshal uses the following type-dependent default encodings:
//
// Boolean values encode as JSON booleans.
//
// Floating point, integer, and Number values encode as JSON numbers.
//
// String values encode as JSON strings coerced to valid UTF-8,
// replacing invalid bytes with the Unicode replacement rune.
// So that the JSON will be safe to embed inside HTML <script> tags,
// the string is encoded using HTMLEscape,
// which replaces "<", ">", "&", U+2028, and U+2029 are escaped
// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".
// This replacement can be disabled when using an Encoder,
// by calling SetEscapeHTML(false).
//
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string, and a nil slice
// encodes as the null JSON value.
//
// Struct values encode as JSON objects.
// Each exported struct field becomes a member of the object, using the
// field name as the object key, unless the field is omitted for one of the
// reasons given below.
//
// The encoding of each struct field can be customized by the format string
// stored under the "json" key in the struct field's tag.
// The format string gives the name of the field, possibly followed by a
// comma-separated list of options. The name may be empty in order to
// specify options without overriding the default field name.
//
// The "omitempty" option specifies that the field should be omitted
// from the encoding if the field has an empty value, defined as
// false, 0, a nil pointer, a nil interface value, and any empty array,
// slice, map, or string.
//
// As a special case, if the field tag is "-", the field is always omitted.
// Note that a field with name "-" can still be generated using the tag "-,".
//
// Examples of struct field tags and their meanings:
//
//   // Field appears in JSON as key "myName".
//   Field int `json:"myName"`
//
//   // Field appears in JSON as key "myName" and
//   // the field is omitted from the object if its value is empty,
//   // as defined above.
//   Field int `json:"myName,omitempty"`
//
//   // Field appears in JSON as key "Field" (the default), but
//   // the field is skipped if empty.
//   // Note the leading comma.
//   Field int `json:",omitempty"`
//
//   // Field is ignored by this package.
//   Field int `json:"-"`
//
//   // Field appears in JSON as key "-".
//   Field int `json:"-,"`
//
// The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. It applies only to fields of string, floating point,
// integer, or boolean types. This extra level of encoding is sometimes used
// when communicating with JavaScript programs:
//
//    Int64String int64 `json:",string"`
//
// The key name will be used if it's a non-empty string consisting of
// only Unicode letters, digits, and ASCII punctuation except quotation
// marks, backslash, and comma.
//
// Anonymous struct fields are usually marshaled as if their inner exported fields
// were fields in the outer struct, subject to the usual Go visibility rules amended
// as described in the next paragraph.
// An anonymous struct field with a name given in its JSON tag is treated as
// having that name, rather than being anonymous.
// An anonymous struct field of interface type is treated the same as having
// that type as its name, rather than being anonymous.
//
// The Go visibility rules for struct fields are amended for JSON when
// deciding which field to marshal or unmarshal. If there are
// multiple fields at the same level, and that level is the least
// nested (and would therefore be the nesting level selected by the
// usual Go rules), the following extra rules apply:
//
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
// even if there are multiple untagged fields that would otherwise conflict.
//
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
//
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
//
// Handling of anonymous struct fields is new in Go 1.1.
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
// an anonymous struct field in both current and earlier versions, give the field
// a JSON tag of "-".
//
// Map values encode as JSON objects. The map's key type must either be a
// string, an integer type, or implement encoding.TextMarshaler. The map keys
// are sorted and used as JSON object keys by applying the following rules,
// subject to the UTF-8 coercion described for string values above:
//   - keys of any string type are used directly
//   - encoding.TextMarshalers are marshaled
//   - integer keys are converted to strings
//
// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON value.
//
// Interface values encode as the value contained in the interface.
// A nil interface value encodes as the null JSON value.
//
// Channel, complex, and function values cannot be encoded in JSON.
// Attempting to encode such a value causes Marshal to return
// an UnsupportedTypeError.
//
// JSON cannot represent cyclic data structures and Marshal does not
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func Marshal(v interface{}) ([]byte, error) {
    e := newEncodeState()

    err := e.marshal(v, encOpts{escapeHTML: true})
    if err != nil {
        return nil, err
    }
    buf := append([]byte(nil), e.Bytes()...)

    e.Reset()
    encodeStatePool.Put(e)

    return buf, nil
}



从上面的Marshal()函数我们可以看到,数据结构序列化后返回的是字节数组,而字节数组很容易通过网络传输或写入文件存储。而且在Go中,Marshal()默认是设置escapeHTML = true的,会自动把 ‘<’, ‘>’, 以及 ‘&’ 等转化为"\u003c" , "\u003e"以及 “\u0026”。

结构体序列化

golang提供了encoding/json的标准库用于编码json。大致需要两步:

1、首先定义json结构体。
2、使用 Marshal方法序列化。

说了这么多,现在就来写一个结构体序列化程序:

package main 

import (
    "fmt"
    "encoding/json"
)

//定义一个结构体
type Monster struct{

    Name string
    Age int
    Birthday string
    Sal float64 
    Skill string

}

//结构体序列化
func main(){

    monster := Monster{
        Name : "minger",
        Age : 23,
        Birthday : "1997-11-13",
        Sal : 2000.0,
        Skill : "Linux C/C++ Go",
    }

    data, err := json.Marshal(&monster)
    if err != nil{
        fmt.Printf("序列号错误 err = %v\n",err)
    }
    fmt.Printf("monster 序列化后= %v\n",string(data)) 

}

输出结果:

如果想验证JSON格式对不对,可以把输出结果放到JSCON验证是否正确。

注意:定义结构体的时候,只有字段名是大写的,才会被编码到json当中。

切片序列化

slice切片,map图则是复合结构。这些结构编码也类似。不过map的key必须是字串,而value必须是同一类型的数据。下面来看看切片序列化程序:

package main 

import (
    "fmt"
    "encoding/json"
)


func main(){


    var slice []map[string]interface{}
    var m1 map[string]interface{}

    //使用map前,需要先make

    m1 = make(map[string]interface{})
    m1["name"] = "minger"
    m1["age"] = 23
    m1["address"] = "中国"
    slice = append(slice,m1) //追加信息

    var m2 map[string]interface{}

    //使用map前,需要先make

    m2 = make(map[string]interface{})
    m2["name"] = "chen"
    m2["age"] = 23
    m2["address"] = "海南"
    slice = append(slice,m2) //追加信息


    data ,err := json.Marshal(slice)
    if err != nil{
        fmt.Printf("序列化错误 err = %v\n",err)
    }
    //输出序列化后的结果
    fmt.Printf("slice 序列化后 = %v\n",string(data))

}


输出结果:

json格式:

[
    {
        "address":"中国",
        "age":23,
        "name":"minger"
    },
    {
        "address":"海南",
        "age":23,
        "name":"chen"
    }
]

map序列化

package main 

import (
    "fmt"
    "encoding/json"
)

//将map进行序列化
func main(){


    //定义一个map

    var a map[string]interface{}
    //使用map,需要make
    a = make(map[string]interface{}) 
    a["name"] = "minger"
    a["age"] = 23
    a["address"] = "china"

    //将a这个map进行序列化
    //将monster 序列化

    data ,err := json.Marshal(a)
    if err != nil{
        fmt.Printf("序列化错误 err = %v\n",err)
    }
    //输出序列化后的结果
    fmt.Printf("map 序列化后 = %v\n",string(data))

}


输出结果:

json格式

{
    "address":"china",
    "age":23,
    "name":"minger"
}

总结

上面所介绍的大致覆盖了golang的json编码处理序列化。总体原则分两步,首先定义需要编码的结构,然后调用encoding/json标准库的Marshal方法生成json byte数组,需要转换成string类型即可。还有基本数据类型 序列化,没有什么意义。

程序猿编码

欢迎关注微信公众号【程序猿编码】,专注于Linux c/c++ 、Python、Go语言、数据结构与算法、网络编程相关知识,常用的程序员工具。还有每日00:10分之前更新新闻简报,即刻知晓天下事!


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:程序猿编码

查看原文:Golang处理JSON(一) 序列化

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3156 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传