【七天入門Go語言】 文件 && 包 | 第五天
目錄
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:
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 := "
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
27
28
2. 包管理
2.1 包路徑
每一個包都通過一個唯一的字符串進行標識,它稱為導入路徑,他們用在import聲明當中。
對于準備共享或公開的包需要全局唯一。當然也要保證沒有循環的導包,循環的導包會引起報錯,而這也就涉及到了程序項目的整體層次結構上了,這點以后再說。
2.2 包聲明
在每一個Go源文件的路徑的最后一段,需要進行聲明。主要目的是當該包被其他包引入的時候作為默認的標識符。
例如在引入 "fmt"之后,可以訪問到它的成員,fmt.Println(),可以注意到這個P是大寫的,說明了,要大寫才能跨包引用。
當我們導用的包的名字沒有在文件中引用的時候,就會有一個編譯錯誤。我們可以使用_來代表
表示導入的內容為空白標識符。
最后
小生凡一,期待你的關注。
Go JSON
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。