Golang標(biāo)準(zhǔn)庫——encoding(2)

  • binary
  • csv
  • gob
  • hex

binary

binary包實(shí)現(xiàn)了簡單的數(shù)字與字節(jié)序列的轉(zhuǎn)換以及變長值的編解碼箩祥。

數(shù)字翻譯為定長值來讀寫志电,一個(gè)定長值骇笔,要么是固定長度的數(shù)字類型(int8, uint8, int16, float32, complex64, ...)或者只包含定長值的結(jié)構(gòu)體或者數(shù)組彻消。

變長值是使用一到多個(gè)字節(jié)編碼整數(shù)的方法竿拆,絕對值較小的數(shù)字會(huì)占用較少的字節(jié)數(shù)。詳情請參見:http://code.google.com/apis/protocolbuffers/docs/encoding.html宾尚。

本包相對于效率更注重簡單丙笋。如果需要高效的序列化,特別是數(shù)據(jù)結(jié)構(gòu)較復(fù)雜的煌贴,請參見更高級的解決方法御板,例如encoding/gob包,或者采用協(xié)議緩存牛郑。

Constants

const (
    MaxVarintLen16 = 3
    MaxVarintLen32 = 5
    MaxVarintLen64 = 10
)

變長編碼N位整數(shù)的最大字節(jié)數(shù)稳吮。

Variables

var BigEndian bigEndian

大端字節(jié)序的實(shí)現(xiàn)。

var LittleEndian littleEndian

小端字節(jié)序的實(shí)現(xiàn)井濒。

type ByteOrder

type ByteOrder interface {
    Uint16([]byte) uint16
    Uint32([]byte) uint32
    Uint64([]byte) uint64
    PutUint16([]byte, uint16)
    PutUint32([]byte, uint32)
    PutUint64([]byte, uint64)
    String() string
}

ByteOrder規(guī)定了如何將字節(jié)序列和 16灶似、32或64比特的無符號整數(shù)互相轉(zhuǎn)化。

func Size

func Size(v interface{}) int

返回v編碼后會(huì)占用多少字節(jié)瑞你,注意v必須是定長值酪惭、定長值的切片、定長值的指針者甲。

func Uvarint

func Uvarint(buf []byte) (uint64, int)

從buf解碼一個(gè)uint64春感,返回該數(shù)字和讀取的字節(jié)長度,如果發(fā)生了錯(cuò)誤虏缸,該數(shù)字為0而讀取長度n返回值的意思是:

    n == 0: buf不完整鲫懒,太短了
    n  < 0: 值太大了,64比特裝不下(溢出)刽辙,-n為讀取的字節(jié)數(shù)

func Varint

func Varint(buf []byte) (int64, int)

從buf解碼一個(gè)int64窥岩,返回該數(shù)字和讀取的字節(jié)長度,如果發(fā)生了錯(cuò)誤宰缤,該數(shù)字為0而讀取長度n返回值的意思是:

    n == 0: buf不完整颂翼,太短了
    n  < 0: 值太大了,64比特裝不下(溢出)慨灭,-n為讀取的字節(jié)數(shù)

func ReadUvarint

func ReadUvarint(r io.ByteReader) (uint64, error)

從r讀取一個(gè)編碼后的無符號整數(shù)信柿,并返回該整數(shù)州弟。

func ReadVarint

func ReadVarint(r io.ByteReader) (int64, error)

從r讀取一個(gè)編碼后的有符號整數(shù),并返回該整數(shù)。

func PutUvarint

func PutUvarint(buf []byte, x uint64) int

將一個(gè)uint64數(shù)字編碼寫入buf并返回寫入的長度量瓜,如果buf太小,則會(huì)panic益老。

func PutVarint

func PutVarint(buf []byte, x int64) int

將一個(gè)int64數(shù)字編碼寫入buf并返回寫入的長度孩革,如果buf太小,則會(huì)panic惶翻。

func Read

func Read(r io.Reader, order ByteOrder, data interface{}) error

從r中讀取binary編碼的數(shù)據(jù)并賦給data姑蓝,data必須是一個(gè)指向定長值的指針或者定長值的切片。從r讀取的字節(jié)使用order指定的字節(jié)序解碼并寫入data的字段里當(dāng)寫入結(jié)構(gòu)體是吕粗,名字中有'_'的字段會(huì)被跳過纺荧,這些字段可用于填充(內(nèi)存空間)。

func main() {
    var pi float64
    b := []byte{0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40}
    buf := bytes.NewReader(b)
    err := binary.Read(buf, binary.LittleEndian, &pi)
    if err != nil {
        fmt.Println("binary.Read failed:", err)
    }
    fmt.Print(pi)
}

func Write

func Write(w io.Writer, order ByteOrder, data interface{}) error

將data的binary編碼格式寫入w颅筋,data必須是定長值宙暇、定長值的切片、定長值的指針议泵。order指定寫入數(shù)據(jù)的字節(jié)序占贫,寫入結(jié)構(gòu)體時(shí),名字中有'_'的字段會(huì)置為0先口。

func main() {
    buf := new(bytes.Buffer)
    var pi float64 = math.Pi
    err := binary.Write(buf, binary.LittleEndian, pi)
    if err != nil {
        fmt.Println("binary.Write failed:", err)
    }
    fmt.Printf("% x", buf.Bytes())
}
func main() {
    buf := new(bytes.Buffer)
    var data = []interface{}{
        uint16(61374),
        int8(-54),
        uint8(254),
    }
    for _, v := range data {
        err := binary.Write(buf, binary.LittleEndian, v)
        if err != nil {
            fmt.Println("binary.Write failed:", err)
        }
    }
    fmt.Printf("%x", buf.Bytes())
}

csv

csv讀寫逗號分隔值(csv)的文件型奥。

一個(gè)csv分揀包含零到多條記錄瞳收,每條記錄一到多個(gè)字段。每個(gè)記錄用換行符分隔厢汹。最后一條記錄后面可以有換行符螟深,也可以沒有。

field1,field2,field3

空白視為字段的一部分烫葬。

換行符前面的回車符會(huì)悄悄的被刪掉界弧。

忽略空行。只有空白的行(除了末尾換行符之外)不視為空行搭综。

以雙引號"開始和結(jié)束的字段成為受引字段垢箕,其開始和結(jié)束的引號不屬于字段。

資源:

normal string,"quoted-field"

產(chǎn)生如下字段:

{`normal string`, `quoted-field`}

受引字段內(nèi)部兑巾,如果有兩個(gè)連續(xù)的雙引號条获,則視為一個(gè)單純的雙引號字符:

"the ""word"" is true","a ""quoted-field"""

生成:

{`the "word" is true`, `a "quoted-field"`}

受引字段里可以包含換行和逗號:

"Multi-line
field","comma is ,"

生成:

{`Multi-line
field`, `comma is ,`}

Variables

var (
    ErrTrailingComma = errors.New("extra delimiter at end of line") // 不再使用
    ErrBareQuote     = errors.New("bare \" in non-quoted-field")
    ErrQuote         = errors.New("extraneous \" in field")
    ErrFieldCount    = errors.New("wrong number of fields in line")
)

這些都是PaserError.Err字段可能的值。

type ParseError

type ParseError struct {
    Line   int   // 出錯(cuò)的行號
    Column int   // 出錯(cuò)的列號
    Err    error // 具體的錯(cuò)誤
}

當(dāng)解析錯(cuò)誤時(shí)返回ParseError闪朱,第一個(gè)行為1月匣,第一列為0。

func (*ParseError) Error

func (e *ParseError) Error() string

type Reader

type Reader struct {
    Comma            rune // 字段分隔符(NewReader將之設(shè)為',')
    Comment          rune // 一行開始位置的注釋標(biāo)識符
    FieldsPerRecord  int  // 每條記錄期望的字段數(shù)
    LazyQuotes       bool // 允許懶引號
    TrailingComma    bool // 忽略奋姿,出于后端兼容性而保留
    TrimLeadingSpace bool // 去除前導(dǎo)的空白
    // 內(nèi)含隱藏或非導(dǎo)出字段
}

Reader從csv編碼的文件中讀取記錄锄开。

NewReader返回的*Reader期望輸入符合RFC 4180。在首次調(diào)用Read或者ReadAll之前可以設(shè)定導(dǎo)出字段的細(xì)節(jié)称诗。

Comma是字段分隔符萍悴,默認(rèn)為','。Comment如果不是0寓免,則表示注釋標(biāo)識符癣诱,以Comment開始的行會(huì)被忽略。如果FieldsPerRecord大于0袜香,Read方法要求每條記錄都有給定數(shù)目的字段撕予。如果FieldsPerRecord等于0,Read方法會(huì)將其設(shè)為第一條記錄的字段數(shù)蜈首,因此其余的記錄必須有同樣數(shù)目的字段实抡。如果FieldsPerRecord小于0,不會(huì)檢查字段數(shù)欢策,允許記錄有不同數(shù)量的字段吆寨。如果LazyQuotes為真,引號可以出現(xiàn)在非受引字段里踩寇,不連續(xù)兩個(gè)的引號可以出現(xiàn)在受引字段里啄清。如果TrimLeadingSpace為真,字段前導(dǎo)的空白會(huì)忽略掉俺孙。

func NewReader

func NewReader(r io.Reader) *Reader

NewReader函數(shù)返回一個(gè)從r讀取的*Reader辣卒。

func (*Reader) Read

func (r *Reader) Read() (record []string, err error)

Read從r讀取一條記錄掷贾,返回值record是字符串的切片,每個(gè)字符串代表一個(gè)字段添寺。

func (*Reader) ReadAll

func (r *Reader) ReadAll() (records [][]string, err error)

ReadAll從r中讀取所有剩余的記錄胯盯,每個(gè)記錄都是字段的切片,成功的調(diào)用返回值err為nil而不是EOF计露。因?yàn)镽eadAll方法定義為讀取直到文件結(jié)尾,因此它不會(huì)將文件結(jié)尾視為應(yīng)該報(bào)告的錯(cuò)誤憎乙。

type Writer

type Writer struct {
    Comma   rune // 字段分隔符(NewWriter將之設(shè)為',')
    UseCRLF bool // 如為真票罐,則換行時(shí)使用\r\n
    // 內(nèi)含隱藏或非導(dǎo)出字段
}

Writer類型的值將記錄寫入一個(gè)csv編碼的文件。

NewWriter返回的*Writer寫入記錄時(shí)泞边,以換行結(jié)束記錄该押,用','分隔字段。在第一次調(diào)用Write或WriteAll之前阵谚,可以設(shè)置導(dǎo)出字段的細(xì)節(jié)蚕礼。

Comma是字段分隔符。如果UseCRLF為真梢什,Writer在每條記錄結(jié)束時(shí)用\r\n代替\n奠蹬。

func NewWriter

func NewWriter(w io.Writer) *Writer

NewWriter返回一個(gè)寫入w的*Writer。

func (*Writer) Write

func (w *Writer) Write(record []string) (err error)

向w中寫入一條記錄嗡午,會(huì)自行添加必需的引號囤躁。記錄是字符串切片,每個(gè)字符串代表一個(gè)字段荔睹。

func (*Writer) WriteAll

func (w *Writer) WriteAll(records [][]string) (err error)

WriteAll方法使用Write方法向w寫入多條記錄狸演,并在最后調(diào)用Flush方法清空緩存。

func (*Writer) Flush

func (w *Writer) Flush()

將緩存中的數(shù)據(jù)寫入底層的io.Writer僻他。要檢查Flush時(shí)是否發(fā)生錯(cuò)誤的話宵距,應(yīng)調(diào)用Error方法。

func (*Writer) Error

func (w *Writer) Error() error

Error返回在之前的Write方法和Flush方法執(zhí)行時(shí)出現(xiàn)的任何錯(cuò)誤吨拗。

func main() {
    file, err := os.OpenFile("test.csv", os.O_CREATE|os.O_RDWR, 0644)
    if err != nil {
        fmt.Println("open file is failed, err: ", err)
    }
    defer file.Close()
    // 寫入U(xiǎn)TF-8 BOM满哪,防止中文亂碼
    file.WriteString("\xEF\xBB\xBF")
    w := csv.NewWriter(file)
    w.Write([]string{"這個(gè)是啥子", "我了個(gè)擦", "發(fā)發(fā)發(fā)"})
    // 寫文件需要flush,不然緩存滿了丢胚,后面的就寫不進(jìn)去了翩瓜,只會(huì)寫一部分
    w.Flush()
}

gob

gob包管理gob流——在編碼器(發(fā)送器)和解碼器(接受器)之間交換的binary值。一般用于傳遞遠(yuǎn)端程序調(diào)用(RPC)的參數(shù)和結(jié)果携龟,如net/rpc包就有提供兔跌。

本實(shí)現(xiàn)給每一個(gè)數(shù)據(jù)類型都編譯生成一個(gè)編解碼程序,當(dāng)單個(gè)編碼器用于傳遞數(shù)據(jù)流時(shí)峡蟋,會(huì)分期償還編譯的消耗坟桅,是效率最高的华望。

Basics

Gob流是自解碼的。流中的所有數(shù)據(jù)都有前綴(采用一個(gè)預(yù)定義類型的集合)指明其類型仅乓。指針不會(huì)傳遞赖舟,而是傳遞值;也就是說數(shù)據(jù)是壓平了的夸楣。遞歸的類型可以很好的工作宾抓,但是遞歸的值(比如說值內(nèi)某個(gè)成員直接/間接指向該值)會(huì)出問題。這個(gè)問題將來可能會(huì)修復(fù)豫喧。

要使用gob石洗,先要?jiǎng)?chuàng)建一個(gè)編碼器,并向其一共一系列數(shù)據(jù):可以是值紧显,也可以是指向?qū)嶋H存在數(shù)據(jù)的指針讲衫。編碼器會(huì)確保所有必要的類型信息都被發(fā)送。在接收端孵班,解碼器從編碼數(shù)據(jù)流中恢復(fù)數(shù)據(jù)并將它們填寫進(jìn)本地變量里涉兽。

Types and Values

發(fā)送端和接收端的值/類型不需要嚴(yán)格匹配。對結(jié)構(gòu)體來說篙程,字段(根據(jù)字段名識別)如果發(fā)送端有而接收端沒有枷畏,會(huì)被忽略;接收端有而發(fā)送端沒有的字段也會(huì)被忽略房午;發(fā)送端和接收端都有的字段其類型必須是可兼容的矿辽;發(fā)送端和接收端都會(huì)在gob流和實(shí)際go類型之間進(jìn)行必要的指針取址/尋址工作。舉例如下:

struct { A, B int }

可以和如下類型互相發(fā)送和接收:

struct { A, B int }   // 同一類型
*struct { A, B int }  // 結(jié)構(gòu)體需要額外重定向(指針)
struct { *A, **B int }    // 字段需要額外重定向(指針)
struct { A, B int64 } // 同為整型/浮點(diǎn)型且符號類型相同的不同值類型郭厌,參見下面

可以發(fā)送給如下任一類型:

struct { A, B int }   // 同一類型
struct { B, A int }   // 字段順序改變無影響袋倔,按名稱匹配
struct { A, B, C int }    // 忽略多出的字段C
struct { B int }  // 忽略缺少的字段A,會(huì)丟棄A的值
struct { B, C int }   // 忽略缺少的字段A折柠,忽略多出的字段C

但嘗試發(fā)送給如下類型的話就會(huì)導(dǎo)致錯(cuò)誤:

struct { A int; B uint }  // B字段改變了符號類型
struct { A int; B float } // B字段改變了類型
struct { }            // 無共同字段名
struct { C, D int }       // 無共同字段名

整數(shù)以兩種方式傳遞:任意精度有符號整數(shù)和任意精度無符號整數(shù)宾娜。Gob里只有無符號和有符號整數(shù)的區(qū)別,沒有int8扇售、int16等類型的區(qū)分前塔。如下所述,發(fā)送端會(huì)以變長編碼發(fā)送整數(shù)值承冰;接收端接收整數(shù)并保存在目標(biāo)變量里华弓。浮點(diǎn)數(shù)則總是使用IEEE-754 64位精度(參見下述)。

有符號整數(shù)可以被任意有符號整形接收:int困乒、int16等寂屏;無符號整數(shù)可以被任意無符號整形接收;浮點(diǎn)數(shù)可以被任意浮點(diǎn)數(shù)類型接收。但是迁霎,接收端類型必須能容納該值(上溢/下溢都不行)吱抚,否則解碼操作會(huì)失敗。

結(jié)構(gòu)體考廉、數(shù)組和切片都被支持秘豹。結(jié)構(gòu)體只編碼和解碼導(dǎo)出字段。字符串和byte數(shù)組/切片有專門的高效表示(參見下述)昌粤。當(dāng)解碼切片時(shí)既绕,如果當(dāng)前切片的容量足夠會(huì)被復(fù)用,否則會(huì)申請新的底層數(shù)組(所以還是用切片地址為好)婚苹。此外岸更,生成的切片的長度會(huì)修改為解碼的成員的個(gè)數(shù)。

Gob流不支持函數(shù)和通道膊升。試圖在最頂層編碼這些類型的值會(huì)導(dǎo)致失敗。結(jié)構(gòu)體中包含函數(shù)或者通道類型的字段的話谭企,會(huì)視作非導(dǎo)出字段(忽略)處理廓译。

Gob可以編碼任意實(shí)現(xiàn)了GobEncoder接口或者encoding.BinaryMarshaler接口的類型的值(通過調(diào)用對應(yīng)的方法),GobEncoder接口優(yōu)先债查。

Gob可以解碼任意實(shí)現(xiàn)了GobDecoder接口或者encoding.BinaryUnmarshaler接口的類型的值(通過調(diào)用對應(yīng)的方法)非区,同樣GobDecoder接口優(yōu)先。

Encoding Details

這部分文檔是編碼細(xì)節(jié)盹廷,對多數(shù)使用者并不重要征绸。細(xì)節(jié)是按從底向上的順序展示的。

無符號整數(shù)用兩種方法發(fā)送俄占。如果該整數(shù)小于128管怠,則以一個(gè)字節(jié)發(fā)送該值;否則采用最小長度大端在前的字節(jié)流保存該整數(shù)缸榄,并在最前面使用一個(gè)字節(jié)保存字節(jié)流的字節(jié)數(shù)相反數(shù)渤弛。因此0被發(fā)送為(00),7被發(fā)送為(07)甚带,而256被發(fā)送為(FE 01 00)(字節(jié)數(shù)2她肯,其相反數(shù)-2,用補(bǔ)碼表示鹰贵,為FE)晴氨。

布爾值按無符號整數(shù)編碼,0表示假碉输,1表示真籽前。

有符號整數(shù)翻譯為一個(gè)無符號整數(shù)(i=>u)來編碼。u的最低字位表示值的符號(以及是否應(yīng)對值按位取反);其余位表示值聚假。編碼算法表示為如下(非實(shí)際代碼):

uint u;
if i < 0 {
  u = (^i << 1) | 1   // i按位取反块蚌,左移1位,第1位設(shè)為1
} else {
  u = (i << 1)    // i不進(jìn)行取反膘格,左移1位峭范,第1位為0
}
encodeUnsigned(u)

這樣一來,最低位就相當(dāng)于標(biāo)志位瘪贱,但還會(huì)對負(fù)數(shù)按位取反纱控,以便保證負(fù)數(shù)不會(huì)出現(xiàn)特殊情況(補(bǔ)碼表示的負(fù)數(shù),其表示會(huì)受到整數(shù)類型的影響)菜秦。如甜害,-129=128=(256>>1)編碼為(FE 01 01)。

浮點(diǎn)數(shù)的數(shù)值球昨,首先總是轉(zhuǎn)換float64類型值尔店,該值使用math.Float64bits 函數(shù)轉(zhuǎn)換為一個(gè)uint64整數(shù),然后將字節(jié)序顛倒過來主慰,最后作為一個(gè)普通無符號數(shù)編碼傳輸嚣州。顛倒字節(jié)序說明數(shù)字的指數(shù)和高精度位數(shù)部分首先傳送。因?yàn)榈臀灰话闶?共螺,這樣可以節(jié)約編碼的字節(jié)數(shù)该肴。例如,17.0編碼后只有三個(gè)字節(jié)(FE 31 40)藐不。

字符串和byte數(shù)組/切片發(fā)送為一個(gè)無符號整數(shù)指定的字節(jié)數(shù)后跟不作處理的字節(jié)序列匀哄。

其它切片和數(shù)組都發(fā)送為一個(gè)無符號整數(shù)指定的成員個(gè)數(shù)后跟所有成員的遞歸表示的gob編碼。

映射發(fā)送為一個(gè)無符號整數(shù)指定的鍵值對數(shù)后給許多鍵和值的gob編碼雏蛮。非nil但無成員的映射也會(huì)發(fā)送涎嚼,因此如果發(fā)送者申請了一個(gè)映射,接收方也會(huì)申請一個(gè)映射底扳,即使該映射內(nèi)沒有元素铸抑。

結(jié)構(gòu)體也以鍵值對(字段名:字段值)序列的形式發(fā)送。字段值采用遞歸表示的gob編碼發(fā)送衷模。如果字段為其類型的零值鹊汛,則該字段不會(huì)被發(fā)送。字段編號由編碼的結(jié)構(gòu)體的類型確定:編碼類型的第一個(gè)字段為字段0阱冶,第二個(gè)為字段1刁憋,依次類推。當(dāng)編碼一個(gè)結(jié)構(gòu)體的值時(shí)木蹬,字段編號出于效率考慮是增量編碼的至耻,字段總是按字段編號遞增的順序被編碼,增量是無符號整數(shù)。增量編碼將字段編號初始化為-1尘颓,因此無符號整型值為7的字段0編碼為增量1值7走触。最后,所有的字段都被發(fā)送后疤苹,會(huì)發(fā)送終止標(biāo)記表明結(jié)構(gòu)體的結(jié)束互广。終止標(biāo)記為一個(gè)增量為0的值,其表示為(00)卧土。

接口類型不會(huì)檢查兼容性惫皱;所有的接口都被視為同一種“接口”類型來傳輸;類似整數(shù)和字節(jié)切片尤莺,它們都被視為interface{}類型旅敷。接口值發(fā)送為一個(gè)表示其具體類型的字符串標(biāo)志符(必須由調(diào)用者預(yù)先注冊的名稱)后跟表示后續(xù)數(shù)據(jù)字節(jié)數(shù)的無符號整數(shù)(以便需要時(shí)可以跳過該值),再后跟保存在接口里的值的動(dòng)態(tài)具體類型的gob編碼颤霎。nil接口值會(huì)發(fā)送為標(biāo)志符為空字符串媳谁、不發(fā)送值的接口。在接收到之后友酱,由解碼器驗(yàn)證該值是否滿足接收端變量接口韩脑。

類型的表示如下所示。當(dāng)一個(gè)編碼器和解碼器的連接中定義了一個(gè)類型時(shí)粹污,該類型會(huì)被指定一個(gè)整數(shù)類型ID。當(dāng)調(diào)用Encoder.Encode(v)時(shí)首量,該方法會(huì)確保v及v所有成員都有對應(yīng)ID壮吩,然后本方法會(huì)發(fā)送一系列對(typeid,encoded-v) 加缘,其中typeid是編碼類型的類型ID鸭叙,encoded-v是值v的gob編碼。

為了定義一個(gè)類型拣宏,編碼器會(huì)選擇一個(gè)未使用的正數(shù)作為id并發(fā)送對(-type id, encoded-type)沈贝,其中encoded-type 是由如下類型構(gòu)成、描述該類型的wireType類型的gob編碼勋乾。

type wireType struct {
  ArrayT  *ArrayType
  SliceT  *SliceType
  StructT *StructType
  MapT    *MapType
}
type arrayType struct {
  CommonType
  Elem typeId
  Len  int
}
type CommonType struct {
  Name string // 結(jié)構(gòu)體的名字
  Id  int    // 類型的ID
}
type sliceType struct {
  CommonType
  Elem typeId
}
type structType struct {
  CommonType
  Field []*fieldType // 結(jié)構(gòu)體的字段
}
type fieldType struct {
  Name string // 字段名
  Id   int    // 字段的類型ID宋下,必須是已經(jīng)定義的類型
}
type mapType struct {
  CommonType
  Key  typeId
  Elem typeId
}

如果有嵌套的類型,必須先定義所有內(nèi)部類型的ID才能定義頂層類型的ID用于描述encoded-v辑莫。

為了簡化啟動(dòng)学歧,有些類型是預(yù)先定義好了的,這些類型及其ID如下:

bool        1
int         2
uint        3
float       4
[]byte      5
string      6
complex     7
interface   8
// 空缺用于保留ID
WireType    16
ArrayType   17
CommonType  18
SliceType   19
StructType  20
FieldType   21
// 22是[]fieldType類型的ID
MapType     23

最后各吨,每一次調(diào)用Encode創(chuàng)建的信息都會(huì)以一個(gè)編碼了的無符號整數(shù)指明消息剩余部分的字節(jié)數(shù)枝笨。在開始的類型名后面,接口值也以同樣的方式包裝;事實(shí)上横浑,接口值表現(xiàn)的就像對Encode進(jìn)行遞歸調(diào)用一樣剔桨。

總的來說,一個(gè)gob流看起來是這樣的:

(byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*

其中*表示0或多次重復(fù)徙融,值的類型id必須是預(yù)定義的洒缀,或者在流中值的前面定義。

參見"Gobs of data"獲取gob wire格式的設(shè)計(jì)討論:

http://golang.org/doc/articles/gobs_of_data.html


type P struct {
    X, Y, Z int
    Name    string
}
type Q struct {
    X, Y *int32
    Name string
}
// This example shows the basic usage of the package: Create an encoder,
// transmit some values, receive them with a decoder.
func Example_basic() {
    // Initialize the encoder and decoder.  Normally enc and dec would be
    // bound to network connections and the encoder and decoder would
    // run in different processes.
    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.
    // Encode (send) some values.
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    err = enc.Encode(P{1782, 1841, 1922, "Treehouse"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) and print the values.
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error 1:", err)
    }
    fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error 2:", err)
    }
    fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)
    // Output:
    // "Pythagoras": {3, 4}
    // "Treehouse": {1782, 1841}
}

func main() {
    Example_basic()
}

type GobDecoder

type GobDecoder interface {
    // GobDecode必須是指針的方法张咳,使用切片數(shù)據(jù)重寫指針指向的值
    // 切片數(shù)據(jù)應(yīng)該由同一具體類型的GobEncode生成
    GobDecode([]byte) error
}

GobDecoder是一個(gè)描述數(shù)據(jù)的接口帝洪,提供自己的方案來解碼GobEncoder發(fā)送的數(shù)據(jù)。

type GobEncoder

type GobEncoder interface {
    // GobEncode方法返回一個(gè)代表值的切片數(shù)據(jù)
    // 該切片數(shù)據(jù)由同一類型的指針方法GobDecoder接受解碼
    GobEncode() ([]byte, error)
}

GobEncoder是一個(gè)描述數(shù)據(jù)的接口脚猾,提供自己的方案來將數(shù)據(jù)編碼供GobDecoder接收并解碼葱峡。一個(gè)實(shí)現(xiàn)了GobEncoder接口和GobDecoder接口的類型可以完全控制自身數(shù)據(jù)的表示,因此可以包含非導(dǎo)出字段龙助、通道砰奕、函數(shù)等數(shù)據(jù),這些數(shù)據(jù)gob流正常是不能傳輸?shù)摹?/p>

注意:因?yàn)間ob數(shù)據(jù)可以被永久保存提鸟,在軟件更新的過程中保證用于GobEncoder編碼的數(shù)據(jù)的穩(wěn)定性(保證兼容)是較好的設(shè)計(jì)原則军援。例如,讓GobEncode 接口在編碼后數(shù)據(jù)里包含版本信息可能很有意義称勋。

func Register

func Register(value interface{})

Register記錄value下層具體值的類型和其名稱胸哥。該名稱將用來識別發(fā)送或接受接口類型值時(shí)下層的具體類型。本函數(shù)只應(yīng)在初始化時(shí)調(diào)用赡鲜,如果類型和名字的映射不是一一對應(yīng)的空厌,會(huì)panic。

func RegisterName

func RegisterName(name string, value interface{})

RegisterName類似Register银酬,淡灰使用提供的name代替類型的默認(rèn)名稱嘲更。

type Decoder

type Decoder struct {
    mutex        sync.Mutex                              // each item must be received atomically
    r            io.Reader                               // source of the data
    buf          decBuffer                               // buffer for more efficient i/o from r
    wireType     map[typeId]*wireType                    // map from remote ID to local description
    decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
    ignorerCache map[typeId]**decEngine                  // ditto for ignored objects
    freeList     *decoderState                           // list of free decoderStates; avoids reallocation
    countBuf     []byte                                  // used for decoding integers while parsing messages
    err          error
}

Decoder管理從連接遠(yuǎn)端讀取的類型和數(shù)據(jù)信息的解釋(的操作)。

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

函數(shù)返回一個(gè)從r讀取數(shù)據(jù)的*Decoder揩瞪,如果r不滿足io.ByteReader接口赋朦,則會(huì)包裝r為bufio.Reader。

func (*Decoder) Decode

func (dec *Decoder) Decode(e interface{}) error

Decode從輸入流讀取下一個(gè)之并將該值存入e李破。如果e是nil宠哄,將丟棄該值;否則e必須是可接收該值的類型的指針喷屋。如果輸入結(jié)束琳拨,方法會(huì)返回io.EOF并且不修改e(指向的值)。

func (*Decoder) DecodeValue

func (dec *Decoder) DecodeValue(v reflect.Value) error

DecodeValue從輸入流讀取下一個(gè)值屯曹,如果v是reflect.Value類型的零值(v.Kind() == Invalid)狱庇,方法丟棄該值惊畏;否則它會(huì)把該值存入v。此時(shí)密任,v必須代表一個(gè)非nil的指向?qū)嶋H存在值的指針或者可寫入的reflect.Value(v.CanSet()為真)颜启。如果輸入結(jié)束,方法會(huì)返回io.EOF并且不修改e(指向的值)浪讳。

type Encoder

type Encoder struct {
    mutex      sync.Mutex              // each item must be sent atomically
    w          []io.Writer             // where to send the data
    sent       map[reflect.Type]typeId // which types we've already sent
    countState *encoderState           // stage for writing counts
    freeList   *encoderState           // list of free encoderStates; avoids reallocation
    byteBuf    encBuffer               // buffer for top-level encoderState
    err        error
}

Encoder管理將數(shù)據(jù)和類型信息編碼后發(fā)送到連接遠(yuǎn)端(的操作)缰盏。

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder返回一個(gè)將編碼后數(shù)據(jù)寫入w的*Encoder。

func (*Encoder) Encode

func (enc *Encoder) Encode(e interface{}) error

Encode方法將e編碼后發(fā)送淹遵,并且會(huì)保證所有的類型信息都先發(fā)送口猜。

func (*Encoder) EncodeValue

func (enc *Encoder) EncodeValue(value reflect.Value) error

EncodeValue方法將value代表的數(shù)據(jù)編碼后發(fā)送,并且會(huì)保證所有的類型信息都先發(fā)送透揣。

type CommonType

type CommonType struct {
    Name string
    Id   typeId
}

CommonType保存所有類型的成員济炎。這是個(gè)歷史遺留“問題”,出于保持binary兼容性才保留辐真,只用于類型描述的編碼须尚。該類型應(yīng)視為不導(dǎo)出類型。

hex

hex包實(shí)現(xiàn)了16進(jìn)制字符表示的編解碼侍咱。

Variables

var ErrLength = errors.New("encoding/hex: odd length hex string")

解碼一個(gè)長度為奇數(shù)的切片時(shí)耐床,將返回此錯(cuò)誤。

type InvalidByteError

type InvalidByteError byte

描述一個(gè)hex編碼字符串中的非法字符楔脯。

func (InvalidByteError) Error

func (e InvalidByteError) Error() string

func DecodedLen

func DecodedLen(x int) int

長度x的編碼數(shù)據(jù)解碼后的明文數(shù)據(jù)的長度

func Decode

func Decode(dst, src []byte) (int, error)

將src解碼為DecodedLen(len(src))字節(jié)撩轰,返回實(shí)際寫入dst的字節(jié)數(shù);如遇到非法字符昧廷,返回描述錯(cuò)誤的error钧敞。

func DecodeString

func DecodeString(s string) ([]byte, error)

返回hex編碼的字符串s代表的數(shù)據(jù)。

func EncodedLen

func EncodedLen(n int) int

長度x的明文數(shù)據(jù)編碼后的編碼數(shù)據(jù)的長度麸粮。

func Encode

func Encode(dst, src []byte) int

將src的數(shù)據(jù)解碼為EncodedLen(len(src))字節(jié),返回實(shí)際寫入dst的字節(jié)數(shù):EncodedLen(len(src))镜廉。

func EncodeToString

func EncodeToString(src []byte) string

將數(shù)據(jù)src編碼為字符串s弄诲。

unc main() {
    src := []byte("abc123")                       // 準(zhǔn)備數(shù)據(jù)
    dst := make([]byte, hex.EncodedLen(len(src))) // 計(jì)算轉(zhuǎn)換為16進(jìn)制后的長度
    hex.Encode(dst, src)                          // 轉(zhuǎn)碼
    fmt.Printf("%s\n", dst)                       // 打印 616263313233,a的ascii碼為97,97轉(zhuǎn)換為16進(jìn)制為61娇唯,后面的bc123同理
    fmt.Println(hex.EncodeToString([]byte("abcdef"))) // 直接將byte切片轉(zhuǎn)為字符串齐遵,打印 616263646566
}

func Dump

func Dump(data []byte) string

返回給定數(shù)據(jù)的hex dump格式的字符串,這個(gè)字符串與控制臺下hexdump -C對該數(shù)據(jù)的輸出是一致的塔插。

func Dumper

func Dumper(w io.Writer) io.WriteCloser

返回一個(gè)io.WriteCloser接口梗摇,將寫入的數(shù)據(jù)的hex dump格式寫入w,具體格式為'hexdump -C'想许。

func main() {
    wd,_ := os.Getwd() // 獲取當(dāng)前工作目錄
    file,_ := os.Create(wd+"/a.txt") // 創(chuàng)建目標(biāo)文件
    w := hex.NewEncoder(file) // 創(chuàng)建一個(gè)流io
    w.Write([]byte("abc")) // 寫入數(shù)據(jù)
    w.Write([]byte("123")) // 寫入數(shù)據(jù)
    // 上面會(huì)將字符 abc123 轉(zhuǎn)換為16進(jìn)制后伶授,寫入到a.txt文件中
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末断序,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子糜烹,更是在濱河造成了極大的恐慌违诗,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疮蹦,死亡現(xiàn)場離奇詭異诸迟,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)愕乎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評論 3 400
  • 文/潘曉璐 我一進(jìn)店門阵苇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人感论,你說我怎么就攤上這事绅项。” “怎么了笛粘?”我有些...
    開封第一講書人閱讀 169,941評論 0 366
  • 文/不壞的土叔 我叫張陵趁怔,是天一觀的道長。 經(jīng)常有香客問我薪前,道長润努,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,294評論 1 300
  • 正文 為了忘掉前任示括,我火速辦了婚禮铺浇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘垛膝。我一直安慰自己鳍侣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評論 6 398
  • 文/花漫 我一把揭開白布吼拥。 她就那樣靜靜地躺著倚聚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凿可。 梳的紋絲不亂的頭發(fā)上惑折,一...
    開封第一講書人閱讀 52,874評論 1 314
  • 那天,我揣著相機(jī)與錄音枯跑,去河邊找鬼惨驶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敛助,可吹牛的內(nèi)容都是我干的粗卜。 我是一名探鬼主播,決...
    沈念sama閱讀 41,285評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼纳击,長吁一口氣:“原來是場噩夢啊……” “哼续扔!你這毒婦竟也來了攻臀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評論 0 277
  • 序言:老撾萬榮一對情侶失蹤测砂,失蹤者是張志新(化名)和其女友劉穎茵烈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砌些,經(jīng)...
    沈念sama閱讀 46,760評論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呜投,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了存璃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仑荐。...
    茶點(diǎn)故事閱讀 40,973評論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖纵东,靈堂內(nèi)的尸體忽然破棺而出粘招,到底是詐尸還是另有隱情,我是刑警寧澤偎球,帶...
    沈念sama閱讀 36,631評論 5 351
  • 正文 年R本政府宣布洒扎,位于F島的核電站,受9級特大地震影響衰絮,放射性物質(zhì)發(fā)生泄漏袍冷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評論 3 336
  • 文/蒙蒙 一猫牡、第九天 我趴在偏房一處隱蔽的房頂上張望胡诗。 院中可真熱鬧,春花似錦淌友、人聲如沸煌恢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瑰抵。三九已至,卻和暖如春器联,著一層夾襖步出監(jiān)牢的瞬間谍憔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評論 1 275
  • 我被黑心中介騙來泰國打工主籍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逛球。 一個(gè)月前我還...
    沈念sama閱讀 49,431評論 3 379
  • 正文 我出身青樓千元,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颤绕。 傳聞我的和親對象是個(gè)殘疾皇子幸海,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評論 2 361