12.1 读取用户的输入

在程序中,程序读取的用户输入口,都是在控制台,即标准输入os.stdin。
可以使用flag包。

  1. func main() {
  2. s := flag.String("n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖
  3. i := flag.Int("i", 1, "-i=1") //i参数,默认1,用法-i=1
  4. flag.Parse() //flag实例
  5. fmt.Println(*s, *i) //吴彦祖 9
  6. }

也可以做参数绑定。

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. )
  6. var (
  7. name string //姓名
  8. age int //年龄
  9. height float64 //身高
  10. )
  11. func main() {
  12. flag.StringVar(&name, "n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖
  13. flag.IntVar(&age, "i", 1, "-i=1") //i参数,默认1,用法-i=1
  14. flag.Float64Var(&height, "h", 1.8, "-h=1.8") //h参数,默认1.8,用法-h=1.8
  15. flag.Parse() //flag实例
  16. fmt.Println("姓名", name)
  17. fmt.Println("年龄", age)
  18. fmt.Println("身高", height)
  19. }

参数绑定有利于做可见性属性,用于其他包导入。

12.2 文件操作

12.2.1 读

文件的读取可以使用os.Open打开文件句柄,然后用bufio包进行字节或字符串读取。

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. )
  8. func main() {
  9. f, err := os.Open("dir.txt") //返回文件句柄
  10. if err != nil {
  11. fmt.Println("文件读取失败", err)
  12. return
  13. }
  14. defer f.Close() //函数调用完就关闭文件句柄
  15. file := bufio.NewReader(f) //返回一个读取器
  16. for {
  17. s, err := file.ReadString('\n') //按行读,行结束符是\n
  18. if err == io.EOF { //文件读取结束
  19. return
  20. }
  21. fmt.Println(s)
  22. }
  23. }

如果是想把整个文件都读入一个字符串中,使用ioutil包。

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. )
  6. func main() {
  7. file, err := ioutil.ReadFile("dir.txt")
  8. if err != nil {
  9. fmt.Println("文件读取失败")
  10. return
  11. }
  12. fmt.Println(string(file))
  13. }

如果想读取压缩文件,可以使用compress包,支持bzip2,flate,gzip,lze和zlib等。

  1. package main
  2. import (
  3. "bufio"
  4. "compress/gzip"
  5. "fmt"
  6. "io"
  7. "os"
  8. )
  9. func main() {
  10. f, err := os.Open("dir.7z")
  11. if err != nil {
  12. fmt.Println("文件读取失败")
  13. return
  14. }
  15. defer f.Close()
  16. fz, err := gzip.NewReader(f)
  17. var r *bufio.Reader
  18. if err != nil {
  19. r = bufio.NewReader(f) //解压失败,可能不是压缩包,则按正常文件读取
  20. } else {
  21. r = bufio.NewReader(fz) //传入解压后的对象
  22. }
  23. for {
  24. line, err := r.ReadString('\n')
  25. if err == io.EOF {
  26. fmt.Println("文件读取结束")
  27. return
  28. }
  29. fmt.Println(line)
  30. }
  31. }

12.2.2 写

写文件先打开文件句柄os.OpenFile,然后使用bufio包写入。

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. )
  7. func main() {
  8. f, err := os.OpenFile("dir.txt", os.O_WRONLY|os.O_CREATE, 0666) //只写,没有文件就创建,权限是0666
  9. if err != nil {
  10. fmt.Println("文件句柄打开失败")
  11. }
  12. defer f.Close()
  13. owriter := bufio.NewWriter(f) //文件写入器
  14. s := "吴彦祖"
  15. for i := 0; i < 10; i++ {
  16. owriter.WriteString(s) //写入器写入字符串,写入到开头
  17. }
  18. owriter.Flush() //刷新
  19. }

12.2.3 复制

文件的拷贝可以使用io包的copy函数。

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. )
  7. func main() {
  8. srcf, err := os.Open("dir.txt")
  9. if err != nil {
  10. fmt.Println("dir.txt文件打开句柄失败")
  11. return
  12. }
  13. defer srcf.Close() //后执行
  14. dstf, err := os.Create("dir-2.txt") //不存在就创建,存在就覆盖
  15. if err != nil {
  16. fmt.Println("目标文件后创建失败")
  17. return
  18. }
  19. defer dstf.Close() //先执行
  20. io.Copy(dstf, srcf)
  21. }

主要defer的顺序,先进后出。

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}

  1. m1 := new(person) //返回指针
  2. json.Unmarshal(j, m1) //反序列化
  3. fmt.Println(*m1) //打印值

}

  1. 要注意,结构体中的属性,首字母一定要**大写**,也就是一定要可导出。<br />要注意m1 := new(person),这里不能m1 := person{},因为反序列化时要使用**指针**,而不是实例。
  2. <a name="NZ82x"></a>
  3. ### 12.3.2 保存到文件
  4. 可以以json的格式将数据保存到文件中,实现持久化。
  5. ```go
  6. package main
  7. import (
  8. "encoding/json"
  9. "os"
  10. )
  11. type person struct {
  12. Name string
  13. Age int
  14. Height float64
  15. }
  16. func main() {
  17. m := person{"吴彦祖", 18, 1.80} //实例化Persion对象
  18. f, _ := os.OpenFile("data.json", os.O_CREATE|os.O_WRONLY, 0666) //打印文件句柄
  19. defer f.Close() //防止忘记关闭句柄
  20. enc := json.NewEncoder(f) //编码器
  21. enc.Encode(m) //编码
  22. }

从文件读json数据的话,就是返过来,解码。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. )
  7. type person struct {
  8. Name string
  9. Age int
  10. Height float64
  11. }
  12. func main() {
  13. m := new(person)
  14. f, _ := os.Open("data.json") //打印文件句柄
  15. defer f.Close() //防止忘记关闭句柄
  16. enc := json.NewDecoder(f) //解码器
  17. enc.Decode(m) //解码
  18. fmt.Println(*m)
  19. }

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)) //吴彦祖181.8

  1. m1 := new(person) //用来存放反序列化后的数据
  2. xml.Unmarshal(x, m1) //反序列化
  3. fmt.Println(*m1) //{吴彦祖 18 1.8}

}

  1. <a name="q7dFB"></a>
  2. ## 12.5 Go中的密码学
  3. 网络数据传输过程中,敏感数据是必须要加密的,以防窃听盗取。<br />一些有关密码学的标准包:
  4. - hash 包:实现了 adler32、crc32、crc64 和 fnv 校验;
  5. - crypto 包:实现了其它的 hash 算法,比如 md4、md5、sha1 等。以及完整地实现了 aes、blowfish、rc4、rsa、xtea 等加密算法。
  6. ```go
  7. //SHA1 例子
  8. package main
  9. import (
  10. "crypto/sha1"
  11. "fmt"
  12. )
  13. func main() {
  14. s := "我是吴彦祖,我为自己带盐"
  15. h := sha1.New() //hash对象
  16. h.Write([]byte(s)) //写入
  17. hashdata := h.Sum(nil) //sum用于追加
  18. fmt.Printf("%x", hashdata) //d3210afa888854036e9fad0e989ae89900042623
  19. }

MD5的计算和sha1是一样的,就是把sha1包换成MD5就行了。

  1. package main
  2. import (
  3. "crypto/md5"
  4. "fmt"
  5. )
  6. func main() {
  7. s := "我是吴彦祖,我为自己带盐"
  8. h := md5.New()
  9. h.Write([]byte(s))
  10. md5data := h.Sum(nil)
  11. fmt.Printf("%x", md5data) //39a0a8f8d78ea57f3762a9e883d9d5d4
  12. }