目录
  • 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.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
            	}
            }
            

            上例中,首先定义了与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)
            

            在上述代码中,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
            	}
            

            要访问解码后的数据结构,需要先判断目标结构是否为预期的数据类型:

            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")
            			}
            		}
            	}
            

            虽然有些烦琐,但的确是一种解码未知结构的 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
            
            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)
            		}
            	}
            }
            
            

            使用 decoder 和 encoder 对数据流进行处理可以应用得更为广泛些,比如读写 http 连接、websocket 或文件等,go 的标准库 net/rpc/jsonrpc 就是一个应用了 decoder 和 encoder的实际例子。

            1.2 xml文件

            xml 数据格式
            对于如下的xml:

            <person>
                <firstname>fan</firstname>
                <lastname>one</lastname>
            </person>
            

            和 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 := "<person><firstname>fan</firstname><lastname>one</lastname></person>"
                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:
                        // ...
                    }
                }
            }
            

            输出:

            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
            

            包中定义了若干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.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.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)
            		}
            }
            

            2. 包管理

            2.1 包路径

            每一个包都通过一个唯一的字符串进行标识,它称为导入路径,他们用在import声明当中。
            对于准备共享或公开的包需要全局唯一。当然也要保证没有循环的导包,循环的导包会引起报错,而这也就涉及到了程序项目的整体层次结构上了,这点以后再说。

            2.2 包声明

            在每一个go源文件的路径的最后一段,需要进行声明。主要目的是当该包被其他包引入的时候作为默认的标识符。

            例如在引入 "fmt"之后,可以访问到它的成员,fmt.println(),可以注意到这个p是大写的,说明了,要大写才能跨包引用。

            当我们导用的包的名字没有在文件中引用的时候,就会有一个编译错误。我们可以使用_来代表

            表示导入的内容为空白标识符。

            以上就是go语言七篇入门教程五文件及包的详细内容,更多关于go语言文件及包的资料请关注www.887551.com其它相关文章!

            如何学习go

            如果你是小白,你可以这样学习go语言~

            七篇入门go语言

            第一篇:go简介初识

            第二篇:

            第三篇:

            第四篇:通道与goroutine的并发编程

            第六篇:

            第七篇:gc垃圾回收三色标记