Go核心开发学习笔记(廿六) —— 文件处理二:命令行处理参数,JSON

关于命令行处理的学习引入:

  1. 假设命令行连接mysql数据库,如何实现下方
    mysql -uroot -p'123456' -h 192.168.240.23 -port 3306 
    
  2. 如果使用os.Args只能按照命令参数输入的顺序来定义序列,不可变。
  3. 引入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概念

  1. JSON:JavaScript Object Notation,轻量级数据交换格式,易于人类阅读,也易于机器解析和生成
  2. 主流的数据格式,YAML和JSON无损互相转换。
  3. JSON有效提升了网路传输效率,程序在网络传输时会先将数据(结构体,map等)序列化成json字符串,接收方得到json字符串,再反序列化恢复成原来的数据类型,这种方式已然成为各个语言的标准。
  4. JS语言中,一切都是对象,因此任何数据类型都可以通过json表示,json键值对是用来保存数据的一种方式。
  5. 字符串,数字,数组,map,结构体都可以作为json数据中的元素。
  6. 格式如下,扩展极为灵活,
    {“key”:“value”,“key”:{“key”:“value”},“key”:[“value1”,“value2”]}
  7. 网站https://www.json.cn 中可以解析json格式,可以调节展开,压缩,转换xml格式等方法。
    举例说明1:
    {"name":"蔡徐坤","hobbies":["唱","跳","rap","篮球"]} 
    解析结果为:
    {
     "name":"蔡徐坤",
     "hobbies":[
         "唱",
         "跳",
         "rap",
         "篮球",
     	]
     }
    
    举例说明2:
    {"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)

  1. 序列化对象:数组,切片,结构体,map
  2. 序列化 string,int,bool等非kv对的数据类型没有任何意义
  3. 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)

  1. B/S结构中,服务器传输json字符串后,浏览器端通过JQuery或JS解析
  2. 反序列化是指将json字符串反序列化成对应的数据类型(json —> map , struct , slice),就是序列化的逆向过程。
  3. ★★★反序列化后的数据类型,要和原来序列化前的数据必须一致!!!如果不一致一定会报错,结构体特殊,字段必须一样,但是数量无所谓
  4. 手写字符串模拟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()
}
发布了49 篇原创文章 · 获赞 18 · 访问量 4000

猜你喜欢

转载自blog.csdn.net/weixin_41047549/article/details/90321373