关于命令行处理的学习引入:
- 假设命令行连接mysql数据库,如何实现下方
mysql -uroot -p'123456' -h 192.168.240.23 -port 3306
- 如果使用os.Args只能按照命令参数输入的顺序来定义序列,不可变。
- 引入package flag,实现了命令行参数的解析。
示例1:使用os.Args统计一个命令包含多少个参数,这样参数传递必须按顺序,无法类似k:v风格改变顺序
package main
import (
"fmt"
"os"
)
func main() {
/*
在命令行中执行 xx.exe 位参1 位参2 ...类型这种方式
使用os.Args 这个是一个切片
打开终端,先讲本代码编译成 *.exe,然后在命令行输入 *.exe 参1 参2 ... 观察结果
*/
fmt.Printf("命令包含的参数个数一共有%d个,分别是:\n",len(os.Args))
for i, v := range os.Args {
fmt.Printf("第%d个参数的值为%v\n",i,v)
}
/*
C:\Users\Administrator>test.exe asd asd aaa
命令包含的参数个数一共有4个,分别是:
第0个参数的值为test.exe第1个参数的值为asd第2个参数的值为asd第3个参数的值为aaa
*/
}
示例2:编写一个mysql登录时所需要的命令行可以乱序的传参,并打印出结果
package main
import (
"flag"
"fmt"
)
func main() {
/*
假设命令行连接mysql数据库: mysql -uroot -p'123456' -h 192.168.240.23 -port 3306 这些东西是如何实现的。
引入flag包,构建出可以乱序的k:v对
常用两个方法,
func StringVar(p *string, name string, value string, usage string)
StringVar用指定的名称、默认值、使用信息注册一个string类型flag,并将flag的值保存到p指向的变量。
func IntVar(p *int, name string, value int, usage string)
IntVar用指定的名称、默认值、使用信息注册一个int类型flag,并将flag的值保存到p指向的变量。
写完上述之后必须使用flag.Parse()来确认生效,不然和不使用write.flush()的后果一样
*/
var user string //建立了四个变量,把他们简化成 -xx的方式
var pwd string
var host string
var port int
flag.StringVar(&user,"u","","用户名默认为空") //参数1指针就是后面 -u 后方的用户名
flag.StringVar(&pwd,"p","","密码默认为空") //参数2为选项,-xx
flag.StringVar(&host,"h","localhost","主机名默认localhost") //参数3为-xx后什么也不填的默认值
flag.IntVar(&port,"port",3306,"数据库默认端口3306") //-port 后面没参数,则参数就是3306
/*
在所有flag都注册之后,调用:
flag.Parse()
来解析命令行参数写入注册的flag里。
*/
flag.Parse() //转换操作,必须使用这种方法,才可以生效,不然拿不到值,必须要在使用之前Parse
fmt.Printf("[user]=%v\n[passwd]=%v\n[host]=%v\n[port]=%v\n",user,pwd,host,port)
}
通过编译生成二进制文件,最后结果为
\# go build -o test1.exe E:\Golear\文件处理\使用flag包解析命令行参数.go
\# test1.exe -u root -p root -h -port
[user]=root
[passwd]=root
[host]=-port
[port]=3306
JSON概念
- JSON:JavaScript Object Notation,轻量级数据交换格式,易于人类阅读,也易于机器解析和生成。
- 主流的数据格式,YAML和JSON无损互相转换。
- JSON有效提升了网路传输效率,程序在网络传输时会先将数据(结构体,map等)序列化成json字符串,接收方得到json字符串,再反序列化恢复成原来的数据类型,这种方式已然成为各个语言的标准。
- JS语言中,一切都是对象,因此任何数据类型都可以通过json表示,json键值对是用来保存数据的一种方式。
- 字符串,数字,数组,map,结构体都可以作为json数据中的元素。
- 格式如下,扩展极为灵活,
{“key”:“value”,“key”:{“key”:“value”},“key”:[“value1”,“value2”]} - 网站https://www.json.cn 中可以解析json格式,可以调节展开,压缩,转换xml格式等方法。
举例说明1:
举例说明2:{"name":"蔡徐坤","hobbies":["唱","跳","rap","篮球"]} 解析结果为: { "name":"蔡徐坤", "hobbies":[ "唱", "跳", "rap", "篮球", ] }
{"name":"蔡徐坤","hobbies":[{"唱":"鸡你太美"},"跳","rap","篮球"]} XML解析结果为: <?xml version="1.0" encoding="UTF-8"?><root> <name>蔡徐坤</name> <hobbies> <唱>鸡你太美</唱> </hobbies> <hobbies>跳</hobbies> <hobbies>rap</hobbies> <hobbies>篮球</hobbies> </root>
JSON如何进行序列化(serialize)
- 序列化对象:数组,切片,结构体,map。
- 序列化 string,int,bool等非kv对的数据类型没有任何意义。
- json序列化是指将存在KV数据类型序列化成json字符串的操作,之前安全培训时候讲过序列化注入,通过改变序列化的一些值进行攻击。
示例3:使用encoding/json来序列化结构体,map,切片,以下示例包含全部知识点
package main
import (
"encoding/json"
"fmt"
)
type Perfo struct { //序列化后的key由我们自行制定,那么就通过反射打个tag
Name string `json:"name"` //反射机制,后续学到再研究
Age int `json:"age"` //如果结构体中字段小写,那么json.Marshal()是另外一个包,这个字段是不可被导入的,也就丢掉了
Hobbies []string `json:"hobbies"` //如果真强制需要小写,那么就只能通过写一个方法,setValue(),getValue()实现了
Skill string `json:"skill"` //这样保持json结构体拿到小写
}
func structSerial() {
//定义结构体变量
var Caixukun Perfo = Perfo{"caixukun",18,[]string{"唱","跳","rap","篮球"},"律师函警告"}
/*
func Marshal(v interface{}) ([]byte, error)
Marshal函数返回一个切片和error
*/
slice, err := json.Marshal(&Caixukun)
if err != nil {
fmt.Println("序列化失败,失败原因为: ",err)
}
fmt.Printf("%T:%v",string(slice),string(slice))
}
func mapSerial() {
//定义一个map,一定要使用make为其开辟内存空间才可以后续使用,不然是无法使用的
var Caixukun1 map[string]interface{}
Caixukun1 = make(map[string]interface{})
Caixukun1["name"] = "蔡徐坤"
Caixukun1["skill"] = "律师函警告"
Caixukun1["hobby"] = []string{"唱","跳","rap","篮球"}
slice, err := json.Marshal(&Caixukun1)
if err != nil {
fmt.Println("序列化失败,失败原因为: ",err)
}
fmt.Printf("%T:%v",string(slice),string(slice))
}
func sliceSerial() {
//定义一个切片,其中添加map数据类型
var slice []map[string]string
var Caixukun2 map[string]string
Caixukun2 = make(map[string]string)
Caixukun2["name"] = "蔡徐坤"
Caixukun2["skill"] = "鸡你太美"
Caixukun2["hobby"] = "唱,跳,rap,篮球"
slice = append(slice,Caixukun2)
var Caixukun3 map[string]string
Caixukun3 = make(map[string]string)
Caixukun3["name"] = "蔡徐坤"
Caixukun3["skill"] = "crush on you"
Caixukun3["hobby"] = "唱,跳,rap,篮球"
slice = append(slice,Caixukun3)
//将切片序列化
slice1, err := json.Marshal(slice)
if err != nil {
fmt.Println("序列化失败,失败原因为: ",err)
}
fmt.Printf("%T:%v",string(slice1),string(slice1))
}
func main() {
//对int,float,string类型序列化后,就是都转成字符串格式,意义不大
//对结构体进行序列化,import encoding/json
//结果为:string {"Name":"caixukun","Age":18,"Hobbies":["唱","跳","rap","篮球"],"Skill":"律师函警告"}
structSerial()
fmt.Println()
//注意map是无序的,如果想排序按照之前对key赋予升序降序的方式排列
//结果为:string:{"hobby":["唱","跳","rap","篮球"],"name":"蔡徐坤","skill":"律师函警告"}
mapSerial()
fmt.Println()
//两个map元素组成的切片
//结果为:string:[{"hobby":"唱,跳,rap,篮球","name":"蔡徐坤","skill":"鸡你太美"},
// {"hobby":"唱,跳,rap,篮球","name":"蔡徐坤","skill":"crush on you"}]
sliceSerial()
//将上述所有序列化后的结果放入www.json.cn里面去查看结果
}
Json的反序列化(unserialize)
- B/S结构中,服务器传输json字符串后,浏览器端通过JQuery或JS解析。
- 反序列化是指将json字符串反序列化成对应的数据类型(json —> map , struct , slice),就是序列化的逆向过程。
- ★★★反序列化后的数据类型,要和原来序列化前的数据必须一致!!!如果不一致一定会报错,结构体特殊,字段必须一样,但是数量无所谓。
- 手写字符串模拟json,必须双引号前加转义,但是通过程序拿到的json已经完成转义,不需要手动添加。
示例4: 把一个json字符串反序列化成结构体,map,切片,以下程序包含全部知识点
package main
import (
"encoding/json"
"fmt"
)
type Perfo1 struct {
Name string `json:"name"`
Age int `json:"age"`
Hobbies []string `json:"hobbies"`
Skill string `json:"skill"`
}
func unserialStruct() {
var Caixukun Perfo1
str := "{\"Name\":\"蔡徐坤\",\"Age\":18,\"Hobbies\":[\"唱\",\"跳\",\"rap\",\"篮球\"],\"Skill\":\"律师函警告\"}"
err := json.Unmarshal([]byte(str), &Caixukun) //err := json.Unmarshal([]byte(string), &<struct结构体变量>)
if err != nil {
fmt.Println("反序列化出现异常,异常报错为:",err)
}
fmt.Println(Caixukun)
}
func unserialMap() {
//map反序列化是不需要先make一个map空间,make函数被封装到Unmarshal()中了。
str := "{\"Name\":\"蔡徐坤\",\"Age\":18,\"Hobbies\":[\"唱\",\"跳\",\"rap\",\"篮球\"],\"Skill\":\"律师函警告\"}"
var cxk map[string]interface{}
err := json.Unmarshal([]byte(str), &cxk) //err := json.Unmarshal([]byte(string), &<map变量>)
if err != nil {
fmt.Println("反序列化出现异常,异常报错为:",err)
}
fmt.Println(cxk)
}
func unserialSlice() {
str := "[{\"hobby\":\"唱,跳,rap,篮球\",\"name\":\"蔡徐坤\",\"skill\":\"鸡你太美\"},{\"hobby\":\"唱,跳,rap,篮球\",\"name\":\"蔡徐坤\",\"skill\":\"crush on you\"}]"
var cxk1 []map[string]string
err := json.Unmarshal([]byte(str), &cxk1) //err := json.Unmarshal([]byte(string), &<map变量>)
if err != nil {
fmt.Println("反序列化出现异常,异常报错为:",err)
}
fmt.Println(cxk1)
}
func main() {
/*
func Unmarshal(data []byte, v interface{}) error
Unmarshal函数解析json编码的数据并将结果存入v指向的值。
解析:
data是一个byte切片,所以对于json string来讲必须要强转一手,string = []byte(string)再传入即可
v 对应的就是要转换成哪个类型,v必须为引用类型,只有引用类型才可以改变函数外部的,也就是假如想反序列化结构体,
就需要如下写法 err := json.Unmarshal([]byte(string), &<struct结构体变量>)
*/
//结果为: {蔡徐坤 18 [唱 跳 rap 篮球] 律师函警告}
unserialStruct()
//结果为:map[Age:18 Hobbies:[唱 跳 rap 篮球] Name:蔡徐坤 Skill:律师函警告]
unserialMap()
//结果为:[map[hobby:唱,跳,rap,篮球 name:蔡徐坤 skill:鸡你太美] map[hobby:唱,跳,rap,篮球 name:蔡徐坤 skill:crush on you]]
unserialSlice()
}