七天入門Go語言】 文件 && 包 | 第五天

      網友投稿 677 2022-05-29

      目錄

      1. 文件處理

      1.1 JSON文件

      1.1.1 已知JSON結構

      1.1.2 未知JSON結構

      1.1.3 Encoder & Decoder

      1.2 XML文件

      1.3 二進制文件

      1.4 zip文件

      1.4.1 創建zip

      1.4.2 讀取zip文件

      2. 包管理

      2.1 包路徑

      2.2 包聲明

      最后

      本章節主要介紹go語言的文件處理與包管理

      1. 文件處理

      1.1 JSON文件

      什么是json?

      JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。

      也是在web開發中的前后端交互的格式。

      encoding/json是官方提供的標準 json, 實現 RFC 7159 中定義的 JSON 編碼和解碼。

      使用的時候需要預定義 struct,原理是通過 reflection 和 interface 來完成工作。

      常用的接口:

      func Marshal(v interface{}) ([]byte, error) // 生成 JSON func Unmarshal(data []byte, v interface{}) error // 解析 JSON 到 struct

      1

      2

      1.1.1 已知JSON結構

      先看例子

      package main import ( "encoding/json" "fmt" ) type Person struct { Name string Age string } type PersonSlice struct { Persons []Person } func main() { var s PersonSlice str := `{"persons":[{"Name":"FanOne","Age":"17"},{"Name":"FanOne2","Age":"18"},{"Name":"FanOne3","Age":"19"}]}` _ = json.Unmarshal([]byte(str), &s) // Golang中提供軟件包"encoding/json"可以直接用來處理JSON文件,此包中解析JSON的函數為Unmarshal // 使用此函數可以將JSON文件解析到結構體中 fmt.Println(s.Persons)//[{FanOne 17} {FanOne2 18} {FanOne3 19}] for _,item:=range s.Persons{ fmt.Println("Name",item.Name,"Age",item.Age) //Name FanOne Age 17 //Name FanOne2 Age 18 //Name FanOne3 Age 19 } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      上例中,首先定義了與json數據對應的結構體,數組對應slice,字段名對應JSON里面的KEY,

      在解析的時候,如何將json數據與struct字段相匹配呢?例如JSON的key是Name,那么怎么找對應的字段呢?

      首先查找tag含有Name的可導出的struct字段(首字母大寫)

      其次查找字段名是Name的導出字段

      最后查找類似NAME或者NaMe這樣的除了首字母之外其他大小寫不敏感的導出字段

      其中需要注意一點:能夠被賦值的字段必須是可導出字段(即首字母大寫)。因為只有首字母大寫才能被外面應用,同時JSON解析的時候只會解析能找得到的字段,找不到的字段會被忽略。

      這樣的一個好處是:當你接收到一個很大的JSON數據結構而你卻只想獲取其中的部分數據的時候,你只需將你想要的數據對應的字段名大寫,即可輕松解決這個問題。

      雖然沒有python直接.json那么方便,但是也還是算不錯的。

      1.1.2 未知JSON結構

      眾所周知,在Go語言中,interface{}可以用來存儲任意數據類型的對象,此數據結構正好用于存儲解析的未知結構的json數據的結果。

      JSON包中采用map[string]interface{}和[]interface{}結構來存儲任意的JSON對象和數組。

      Go類型和JSON類型的對應關系如下:

      bool 代表 JSON booleans,

      float64 代表 JSON numbers,

      string 代表 JSON strings,

      nil 代表 JSON null.

      b := []byte(`{ "Name": "FanOne", "School": ["FZU", "XCZX", "UUUU", "GuaguaSong", "HanTuo", "City", "FuZhou"], "Major": "BigData", "IsPublished": true, "Price": 9.99, "Sales": 1000000 }`) var r interface{} err := json.Unmarshal(b, &r)

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      在上述代碼中,r 被定義為一個空接口。

      json.Unmarshal()函數將一個 JSON 對象解碼

      到空接口 r 中,最終 r 將會是一個鍵值對的map[string]interface{}結構:

      map[string]interface{}{ "Name": "FanOne", "School": ["FZU", "XCZX", "UUUU", "GuaguaSong", "HanTuo", "City", "FuZhou"], "Major": "BigData", "IsPublished": true, "Price": 9.99, "Sales": 1000000 }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      要訪問解碼后的數據結構,需要先判斷目標結構是否為預期的數據類型:

      gobook, ok := r.(map[string]interface{})

      然后,我們可以通過 for 循環搭配 range 語句一一訪問解碼后的目標數據:

      if ok { for k, v := range gobook { switch v2 := v.(type) { case string: fmt.Println(k, "is string", v2) case int: fmt.Println(k, "is int", v2) case bool: fmt.Println(k, "is bool", v2) case []interface{}: fmt.Println(k, "is an array:") for i, iv := range v2 { fmt.Println(i, iv) } default: fmt.Println(k, "is another type not handle yet") } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      雖然有些煩瑣,但的確是一種解碼未知結構的 JSON 數據的安全方式。

      1.1.3 Encoder & Decoder

      Go 內建的 encoding/json 包還提供 Decoder 和 Encoder 兩個類型,用于支持 JSON 數據的流式讀寫,并提供 NewDecoder()和 NewEncoder()兩個函數來便于具體實現:

      func NewDecoder(r io.Reader) *Decoder func NewEncoder(w io.Writer) *Encoder

      1

      2

      func main() { dec := json.NewDecoder(os.Stdin) enc := json.NewEncoder(os.Stdout) for { var v map[string]interface{} if err := dec.Decode(&v); err != nil{ log.Println(err) return } for k := range v { if k != "Name" { v[k] = nil,false } } if err := enc.Encode(&v); err != nil{ log.Println(err) } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      使用 Decoder 和 Encoder 對數據流進行處理可以應用得更為廣泛些,比如讀寫 HTTP 連接、WebSocket 或文件等,Go 的標準庫 net/rpc/jsonrpc 就是一個應用了 Decoder 和 Encoder的實際例子。

      1.2 XML文件

      XML 數據格式

      對于如下的XML:

      Fan One

      1

      2

      3

      4

      和 JSON 的方式一樣,XML 數據可以序列化為結構,或者從結構反序列化為 XML 數據;

      encoding/xml包實現了一個簡單的 XML 解析器(SAX),用來解析 XML 數據內容。下面的例子說明如何使用解析器:

      復制代碼 // xml.go package main import ( "encoding/xml" "fmt" "strings" ) var t, token xml.Token var err error func main() { input := "FanOne" inputReader := strings.NewReader(input) p := xml.NewDecoder(inputReader) for t, err = p.Token(); err == nil; t, err = p.Token() { switch token := t.(type) { case xml.StartElement: name := token.Name.Local fmt.Printf("Token name: %s\n", name) for _, attr := range token.Attr { attrName := attr.Name.Local attrValue := attr.Value fmt.Printf("An attribute is: %s %s\n", attrName, attrValue) } case xml.EndElement: fmt.Println("End of token") case xml.CharData: content := string([]byte(token)) fmt.Printf("This is the content: %v\n", content) // ... default: // ... } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      輸出:

      Token name: Person Token name: FirstName This is the content: Fan End of token Token name: LastName This is the content: One End of token End of token

      1

      2

      3

      4

      5

      6

      7

      8

      包中定義了若干XML 標簽類型:StartElement,Chardata(這是從開始標簽到結束標簽之間的實際文本)EndElement,Comment,Directive 或 ProcInst。

      包中同樣定義了一個結構解析器:

      NewParser 方法持有一個 io.Reader(這里具體類型是strings.NewReader)并生成一個解析器類型的對象。

      還有一個 Token() 方法返回輸入流里的下一個 XML token。在輸入流的結尾處,會返回(nil,io.EOF)

      XML 文本被循環處理直到 Token() 返回一個錯誤,因為已經到達文件尾部,再沒有內容可供處理了。

      通過一個 type-switch 可以根據一些 XML 標簽進一步處理。Chardata中的內容只是一個 []byte,通過字符串轉換讓其變得可讀性強一些。

      1.3 二進制文件

      go語言可以在win下進行如下的設置將go程序build成二進制文件

      set CGO_ENABLED = 0 set GOOS = linux set GOARCH = amd64 go build main.go

      1

      2

      3

      4

      1.4 zip文件

      1.4.1 創建zip

      Go語言提供了archive/zip包來處理zip壓縮文件

      func createZip(filename string) { // 緩存壓縮文件內容 buf := new(bytes.Buffer) // 創建zip writer := zip.NewWriter(buf) defer writer.Close() // 讀取文件內容 content, _ := ioutil.ReadFile(filepath.Clean(filename)) // 接收 f, _ := writer.Create(filename) f.Write(content) filename = strings.TrimSuffix(filename, path.Ext(filename)) + ".zip" ioutil.WriteFile(filename, buf.Bytes(), 0644) }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      1.4.2 讀取zip文件

      讀取zip文檔過程與創建zip文檔過程類似,需要解壓后的文檔目錄結構創建:

      func readZip(filename string) { zipFile, err := zip.OpenReader(filename) // 打開zip文件 if err != nil { panic(err.Error()) } defer zipFile.Close() for _, f := range zipFile.File { // 循環讀取zip中的內容 info := f.FileInfo() if info.IsDir() { err = os.MkdirAll(f.Name, os.ModePerm) if err != nil { panic(err.Error()) } continue } srcFile, err := f.Open() // 打開文件 if err != nil { panic(err.Error()) } defer srcFile.Close() newFile, err := os.Create(f.Name) if err != nil { panic(err.Error()) } defer newFile.Close() io.Copy(newFile, srcFile) } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      【七天入門Go語言】 文件 && 包 | 第五天

      27

      28

      2. 包管理

      2.1 包路徑

      每一個包都通過一個唯一的字符串進行標識,它稱為導入路徑,他們用在import聲明當中。

      對于準備共享或公開的包需要全局唯一。當然也要保證沒有循環的導包,循環的導包會引起報錯,而這也就涉及到了程序項目的整體層次結構上了,這點以后再說。

      2.2 包聲明

      在每一個Go源文件的路徑的最后一段,需要進行聲明。主要目的是當該包被其他包引入的時候作為默認的標識符。

      例如在引入 "fmt"之后,可以訪問到它的成員,fmt.Println(),可以注意到這個P是大寫的,說明了,要大寫才能跨包引用。

      當我們導用的包的名字沒有在文件中引用的時候,就會有一個編譯錯誤。我們可以使用_來代表

      表示導入的內容為空白標識符。

      最后

      小生凡一,期待你的關注。

      Go JSON

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Docker之快速搞定容器數據卷
      下一篇:Lucene高性能索引之道
      相關文章
      亚洲一区二区三区无码影院| 亚洲av无码专区在线电影天堂| 亚洲avav天堂av在线不卡 | 成人亚洲国产va天堂| 亚洲色图在线观看| 亚洲精品蜜桃久久久久久| 亚洲JIZZJIZZ中国少妇中文| 亚洲爆乳无码精品AAA片蜜桃| 亚洲综合色一区二区三区| 亚洲精品福利你懂| 亚洲天堂一区二区三区四区| 亚洲天堂中文字幕| 亚洲av鲁丝一区二区三区| 亚洲AV无码一区二区三区DV| 亚洲精品乱码久久久久久| 亚洲啪啪AV无码片| 亚洲人成影院在线无码按摩店| 久久久精品国产亚洲成人满18免费网站| 国产精品亚洲精品日韩电影| 337P日本欧洲亚洲大胆艺术图| AV激情亚洲男人的天堂国语| 亚洲欧美自偷自拍另类视| 亚洲kkk4444在线观看| 亚洲国产成人久久三区| 最新国产成人亚洲精品影院| 亚洲无码一区二区三区| 亚洲最大的成人网| 老司机亚洲精品影院在线观看| 自拍偷自拍亚洲精品播放| 亚洲精品V天堂中文字幕| 亚洲精品9999久久久久无码| 亚洲AV成人片无码网站| 亚洲国产一区视频| 亚洲情侣偷拍精品| 在线播放亚洲第一字幕| 亚洲第一AV网站| 亚洲香蕉免费有线视频| 亚洲av成人综合网| 亚洲国产欧洲综合997久久| 无码国产亚洲日韩国精品视频一区二区三区| 日韩亚洲国产二区|