12.1 读取用户的输入
在程序中,程序读取的用户输入口,都是在控制台,即标准输入os.stdin。
可以使用flag包。
func main() {s := flag.String("n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖i := flag.Int("i", 1, "-i=1") //i参数,默认1,用法-i=1flag.Parse() //flag实例fmt.Println(*s, *i) //吴彦祖 9}
也可以做参数绑定。
package mainimport ("flag""fmt")var (name string //姓名age int //年龄height float64 //身高)func main() {flag.StringVar(&name, "n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖flag.IntVar(&age, "i", 1, "-i=1") //i参数,默认1,用法-i=1flag.Float64Var(&height, "h", 1.8, "-h=1.8") //h参数,默认1.8,用法-h=1.8flag.Parse() //flag实例fmt.Println("姓名", name)fmt.Println("年龄", age)fmt.Println("身高", height)}
12.2 文件操作
12.2.1 读
文件的读取可以使用os.Open打开文件句柄,然后用bufio包进行字节或字符串读取。
package mainimport ("bufio""fmt""io""os")func main() {f, err := os.Open("dir.txt") //返回文件句柄if err != nil {fmt.Println("文件读取失败", err)return}defer f.Close() //函数调用完就关闭文件句柄file := bufio.NewReader(f) //返回一个读取器for {s, err := file.ReadString('\n') //按行读,行结束符是\nif err == io.EOF { //文件读取结束return}fmt.Println(s)}}
如果是想把整个文件都读入一个字符串中,使用ioutil包。
package mainimport ("fmt""io/ioutil")func main() {file, err := ioutil.ReadFile("dir.txt")if err != nil {fmt.Println("文件读取失败")return}fmt.Println(string(file))}
如果想读取压缩文件,可以使用compress包,支持bzip2,flate,gzip,lze和zlib等。
package mainimport ("bufio""compress/gzip""fmt""io""os")func main() {f, err := os.Open("dir.7z")if err != nil {fmt.Println("文件读取失败")return}defer f.Close()fz, err := gzip.NewReader(f)var r *bufio.Readerif err != nil {r = bufio.NewReader(f) //解压失败,可能不是压缩包,则按正常文件读取} else {r = bufio.NewReader(fz) //传入解压后的对象}for {line, err := r.ReadString('\n')if err == io.EOF {fmt.Println("文件读取结束")return}fmt.Println(line)}}
12.2.2 写
写文件先打开文件句柄os.OpenFile,然后使用bufio包写入。
package mainimport ("bufio""fmt""os")func main() {f, err := os.OpenFile("dir.txt", os.O_WRONLY|os.O_CREATE, 0666) //只写,没有文件就创建,权限是0666if err != nil {fmt.Println("文件句柄打开失败")}defer f.Close()owriter := bufio.NewWriter(f) //文件写入器s := "吴彦祖"for i := 0; i < 10; i++ {owriter.WriteString(s) //写入器写入字符串,写入到开头}owriter.Flush() //刷新}
12.2.3 复制
文件的拷贝可以使用io包的copy函数。
package mainimport ("fmt""io""os")func main() {srcf, err := os.Open("dir.txt")if err != nil {fmt.Println("dir.txt文件打开句柄失败")return}defer srcf.Close() //后执行dstf, err := os.Create("dir-2.txt") //不存在就创建,存在就覆盖if err != nil {fmt.Println("目标文件后创建失败")return}defer dstf.Close() //先执行io.Copy(dstf, srcf)}
12.3 json数据
json,xml等数据结构在网络传输过程中,必须经过编码和解码,提高其可读性。
- 数据结构 —> 指定格式 = 序列化 或 编码(传输之前)
- 指定格式 —> 数据结构 = 反序列化 或 解码(传输之后)
12.3.1 序列化和反序列化
使用json包的Marsha1函数进行序列化成json数据。 ```go package main
import ( “encoding/json” “fmt” )
type person struct { Name string Age int Height float64 }
func main() { m := person{“吴彦祖”, 18, 1.80} //实例化Persion对象 j, _ := json.Marshal(m) //序列化 fmt.Println(string(j)) //{“Name”:”吴彦祖”,”Age”:18,”Height”:1.8}
m1 := new(person) //返回指针json.Unmarshal(j, m1) //反序列化fmt.Println(*m1) //打印值
}
要注意,结构体中的属性,首字母一定要**大写**,也就是一定要可导出。<br />要注意m1 := new(person),这里不能m1 := person{},因为反序列化时要使用**指针**,而不是实例。<a name="NZ82x"></a>### 12.3.2 保存到文件可以以json的格式将数据保存到文件中,实现持久化。```gopackage mainimport ("encoding/json""os")type person struct {Name stringAge intHeight float64}func main() {m := person{"吴彦祖", 18, 1.80} //实例化Persion对象f, _ := os.OpenFile("data.json", os.O_CREATE|os.O_WRONLY, 0666) //打印文件句柄defer f.Close() //防止忘记关闭句柄enc := json.NewEncoder(f) //编码器enc.Encode(m) //编码}
从文件读json数据的话,就是返过来,解码。
package mainimport ("encoding/json""fmt""os")type person struct {Name stringAge intHeight float64}func main() {m := new(person)f, _ := os.Open("data.json") //打印文件句柄defer f.Close() //防止忘记关闭句柄enc := json.NewDecoder(f) //解码器enc.Decode(m) //解码fmt.Println(*m)}
12.3.3 json支持的格式
并不是所有的数据类型都可以编码成json类型的:
- JSON 对象只支持字符串类型的 key;要编码一个 Go map 类型,map 必须是 map[string]T(T 是 json 包中支持的任何类型)
- Channel,复杂类型和函数类型不能被编码
- 不支持循环数据结构;它将引起序列化进入一个无限循环
- 指针可以被编码,实际上是对指针指向的值进行编码(或者指针是 nil)
12.4 xml数据
xml和json的做法几乎是一模一样的,就是把json包换成xml包即可。12.4.1 序列化和反序列化
```go package main
import ( “encoding/xml” “fmt” )
type person struct { Name string Age int Height float64 }
func main() {
m := person{“吴彦祖”, 18, 1.80}
x, _ := xml.Marshal(m)
fmt.Println(string(x)) //
m1 := new(person) //用来存放反序列化后的数据xml.Unmarshal(x, m1) //反序列化fmt.Println(*m1) //{吴彦祖 18 1.8}
}
<a name="q7dFB"></a>## 12.5 Go中的密码学网络数据传输过程中,敏感数据是必须要加密的,以防窃听盗取。<br />一些有关密码学的标准包:- hash 包:实现了 adler32、crc32、crc64 和 fnv 校验;- crypto 包:实现了其它的 hash 算法,比如 md4、md5、sha1 等。以及完整地实现了 aes、blowfish、rc4、rsa、xtea 等加密算法。```go//SHA1 例子package mainimport ("crypto/sha1""fmt")func main() {s := "我是吴彦祖,我为自己带盐"h := sha1.New() //hash对象h.Write([]byte(s)) //写入hashdata := h.Sum(nil) //sum用于追加fmt.Printf("%x", hashdata) //d3210afa888854036e9fad0e989ae89900042623}
MD5的计算和sha1是一样的,就是把sha1包换成MD5就行了。
package mainimport ("crypto/md5""fmt")func main() {s := "我是吴彦祖,我为自己带盐"h := md5.New()h.Write([]byte(s))md5data := h.Sum(nil)fmt.Printf("%x", md5data) //39a0a8f8d78ea57f3762a9e883d9d5d4}
