第07天-进阶-接口实例、终端文件读写、异常处理

本节主要内容:

1. 终端读写
2. 文件读写
3. 命令行参数
4. Json
5. 自定义错误
6. 课后作业

1. 终端读写

   操作终端相关文件句柄常量
    os.Stdin:标准输入
    os.Stdout:标准输出
    os.Stderr:标准错误输出

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 var (
 8     firstName, lastName, s string
 9     i                      int
10     f                      float32
11     input                  = "56.12 / 5212 / Go"
12     format                = "%f / %d / %s"
13 )
14 
15 func main() {
16     fmt.Println("Please enter your full name: ") //Chris Naegels
17     fmt.Scanln(&firstName, &lastName) //和下面等价
18     // fmt.Scanf("%s %s", &firstName, &lastName)
19     fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels!
20     fmt.Sscanf(input, format, &f, &i, &s)
21     fmt.Println("From the string we read: ", f, i, s) //From the string we read:  56.12 5212 Go
22 }
example
 1 package main 
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "os"
 7 )
 8 
 9 func main() {
10     fmt.Println("Input string >>")
11     reader := bufio.NewReader(os.Stdin)
12     res, err := reader.ReadString('\n')
13     if err != nil {
14         fmt.Println("Read failed, Error: ", err)
15     }
16     fmt.Printf("Read success, content: ", res)
17 }
从终端读入
 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "bufio"
 7 )
 8 
 9 func main() {
10     // fmt.Fprintf(os.Stdout, "%s\n", "hello world")
11 
12     buf := bufio.NewWriter(os.Stdout)
13     fmt.Fprintf(buf, "%s\n", "hello world")
14     buf.Flush()
15 }
带缓冲区的终端读写

2. 文件读写

   (1)文件读取

    bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。
    实际上在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据;只有当缓冲区没有数据  时,才会从数据源获取数据更新缓冲。

 1 package main 
 2 
 3 import (
 4     "os"
 5     "fmt"
 6     "bufio"
 7 )
 8 
 9 func main() {
10     var input *bufio.Reader
11     var str string
12     var err error
13 
14     input = bufio.NewReader(os.Stdin)
15     str, err = input.ReadString('\n') //注意:ReadString会返回读取的字符串(包括分隔符'\n')
16     if err != nil {
17         fmt.Println("Read failed")
18     }
19     fmt.Println("Read success, content: ", str)
20 }
example

练习: 从终端读取一行字符串,统计英文、数字、空格以及其他字符的数量。

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "bufio"
 7     "strings"
 8 )
 9 
10 type CharCount struct {
11     ChCount int
12     NumCount int
13     SpaceCount int
14     OtherCount int
15 }
16 
17 func Count(str string, cc *CharCount) {
18     runeArr := []rune(str)
19     for _, v := range runeArr {
20         fmt.Printf("--%v\n",v)
21         switch {
22         case v >= 'A' && v <= 'Z':
23             fallthrough
24         case v >= 'a' && v <= 'z':
25             cc.ChCount++
26         case v >= '0' && v <= '9':
27             cc.NumCount++
28         case v == ' ':
29             cc.SpaceCount++
30         default:
31             cc.OtherCount++
32         }
33     }
34 }
35 
36 func main() {
37     var cc CharCount
38 
39     fmt.Println("Input string >>")
40     reader := bufio.NewReader(os.Stdin)
41     str, err := reader.ReadString('\n')
42     if err != nil {
43         fmt.Println("Read failed")
44     }
45 
46     str = strings.Trim(string(str), "\r\n") //去掉末尾的\r\n,否则OtherCount会多加2
47 
48     Count(string(str), &cc)
49     fmt.Println(cc)
50 }
从terminal读取

     os.File封装所有文件相关操作,之前讲的 os.Stdin,os.Stdout, os.Stderr都是*os.File
     a. 打开一个文件进行读操作: os.Open(name string) (*File, error)
     b. 关闭一个文件:File.Close()

     1)将整个文件读取到内存

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "io/ioutil"
 6 )
 7 
 8 func main() {
 9     fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
10     data, err := ioutil.ReadFile(fileName)
11     if err != nil {
12     fmt.Println("File reading error", err)
13     return
14     }
15     fmt.Println("Contents of file: ", string(data))
16 }
读取整个文件

    2)分块读取文件
         在前面的章节,我们学习了如何把整个文件读取到内存。当文件非常大时,尤其在 RAM 存储量不足的情况下,把整个文件都读入内存是没有意义的。更好的方法是分块读取文件。这可以使用 bufio 包来完成。

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "log"
 7     "os"
 8     "io"
 9 )
10 
11 func EmptyArray(arr []byte) {
12     for i := 0; i < len(arr); i++ {
13         arr[i] = 0
14     }
15 }
16 
17 func main() {
18     fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
19 
20     f, err := os.Open(fileName)
21     if err != nil {
22         log.Fatal(err)
23     }
24 
25     defer func() {
26         if err = f.Close(); err != nil {
27             log.Fatal(err)
28         }
29     }()
30 
31     var str string
32     r := bufio.NewReader(f)
33     b := make([]byte, 3)  //每次读取3个字节
34 
35     for {
36         EmptyArray(b)
37 
38         _, err := r.Read(b)
39         if err == io.EOF {
40             fmt.Println("Read finish")
41             break
42         }
43 
44         if err != nil {
45             fmt.Println("Error reading file: ", err)
46             break
47         }
48         str = string(b)
49         fmt.Printf("%s", str)
50     }
51 }
分块读取

    3)逐行读取文件

 1 package main
 2 
 3 import (
 4     "bufio"
 5     "fmt"
 6     "log"
 7     "os"
 8 )
 9 
10 func main() {
11     fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
12 
13     f, err := os.Open(fileName)
14     if err != nil {
15         log.Fatal(err)
16     }
17 
18     defer func() {
19         if err = f.Close(); err != nil {
20         log.Fatal(err)
21     }
22     }()
23 
24     s := bufio.NewScanner(f)
25     for s.Scan() {
26         fmt.Println(s.Text())
27     }
28     
29     if err = s.Err(); err != nil {
30         log.Fatal(err)
31     }
32 }
逐行读取

练习:读取压缩文件(zip)

 1 package main
 2 
 3 // 引入所需包
 4 import (
 5     "os"
 6     "compress/gzip"
 7     "io/ioutil"
 8     "fmt"
 9 )
10 
11 // gzip文件
12 
13 
14 func main() {
15     fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.zip"
16     // 打开本地gz格式压缩包
17     fr, err := os.Open(fileName)
18     if err != nil {
19         panic(err)
20     } else {
21         println("open file success!")
22     }
23 
24     // defer: 在函数退出时,执行关闭文件
25     defer fr.Close()
26 
27     // 创建gzip文件读取对象
28     gr, err := gzip.NewReader(fr)
29     if err != nil {
30             panic(err)
31         }
32 
33     // defer: 在函数退出时,执行关闭gzip对象
34     defer gr.Close()
35 
36     // 读取gzip对象内容
37     rBuf, err := ioutil.ReadAll(gr)
38     if err != nil {
39         fmt.Println("[read gzip data err]: ", err)
40     }
41 
42     // 以文本形式输出
43     fmt.Printf("%s\n", rBuf)
44 }
读取压缩文件示例

   (2)文件写入

           os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)

第二个参数:文件打开模式:
1. os.O_WRONLY:只写
2. os.O_CREATE:创建文件
3. os.O_RDONLY:只读
4. os.O_RDWR:读写
5. os.O_TRUNC :清空
第三个参数:权限控制:
r ——> 004
w ——> 002
x ——> 001
 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "bufio"
 7 )
 8 
 9 func main() {
10     filePath := "F:\\Go\\project\\src\\go_dev\\day7\\write_test.txt"
11     outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
12     if err != nil {
13         fmt.Println("Failed to write file")
14         return
15     }
16     defer outFile.Close()
17 
18     outWrite := bufio.NewWriter(outFile)
19     des := "hello world!\n"
20     for i := 0; i < 10; i++ {
21         outWrite.WriteString(des)
22     }
23     outWrite.Flush()
24 }
example

    (3)拷贝文件

 1 package main 
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "io"
 7 )
 8 
 9 //A successful Copy returns err == nil, not err == EOF
10 func CopyFile(destName, srcName string) (written int64, err error) {
11     src, err := os.Open(srcName)
12     if err != nil {
13         panic(err)
14     }
15     defer src.Close()
16 
17     dest, err := os.OpenFile(destName, os.O_WRONLY|os.O_CREATE, 0666)
18     if err != nil {
19         panic(err)
20     }
21     defer dest.Close()
22 
23     return io.Copy(dest, src)
24 }
25 
26 func main() {
27     srcName := "F:\\Go\\project\\src\\go_dev\\day7\\write_test.txt"
28     destName := "F:\\Go\\project\\src\\go_dev\\day7\\dest_test.txt"
29 
30     wByte, err := CopyFile(destName, srcName)
31     if err != nil {
32         fmt.Println("Copy failed")
33     } else {
34         fmt.Printf("Copy %d byte from src to dest\n", wByte)
35     }
36 }
Copy

3. 命令行参数

    os.Args是一个string的切片,用来存储所有的命令行参数
    flag包的使用,用来解析命令行参数:

flag.BoolVar(&test, "b", false, "print on newline")
flag.StringVar(&str, "s", "", "print on newline")
flag.IntVar(&count, "c", 1001, "print on newline")
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6 )
 7 
 8 func main() {
 9     fmt.Printf("len of args:%d\n", len(os.Args))
10     for i, v := range os.Args {
11         fmt.Printf("args[%d]=%s\n", i, v)
12     }
13 }
14 
15 //输入:
16 //go run main7.go hello world
17 // 输出:
18 // len of args:3
19 // args[0]=C:\Users\ADMINI~1\AppData\Local\Temp\go-build596136718\command-line-argu
20 // ments\_obj\exe\main7.exe
21 // args[1]=hello
22 // args[2]=world
example
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "flag"
 6 )
 7 
 8 func main() {
 9     var configPath string
10     var logLevel int
11 
12     flag.StringVar(&configPath, "c", "", "Please config path")
13     flag.IntVar(&logLevel, "d", 10, "Please log level")
14 
15     flag.Parse()
16 
17     fmt.Println("configPath: ", configPath)
18     fmt.Println("logLevel: ", logLevel)
19 }
example2

4. Json数据协议

func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error
导入包:import "encoding/json"
序列化: json.Marshal(data interface{})
反序列化: json.UnMarshal(data []byte, v interface{})

练习:json序列化结构体

 1 package main
 2 
 3 import (
 4     "encoding/json"
 5     "fmt"
 6 )
 7 
 8 type User struct {
 9     UserName string `json:"username"`
10     NickName string `json:"nickname"`
11     Age      int
12     Birthday string
13     Sex      string
14     Email    string
15     Phone    string
16 }
17 
18 func testStruct() {
19     user1 := &User{
20         UserName: "user1",
21         NickName: "上课看似",
22         Age:      18,
23         Birthday: "2008/8/8",
24         Sex:      "",
25         Email:    "[email protected]",
26         Phone:    "110",
27     }
28 
29     data, err := json.Marshal(user1)
30     if err != nil {
31         fmt.Printf("json.marshal failed, err:", err)
32         return
33     }
34 
35     fmt.Printf("%s\n", string(data))
36 }
37 
38 func testInt() {
39     var age = 100
40     data, err := json.Marshal(age)
41     if err != nil {
42         fmt.Printf("json.marshal failed, err:", err)
43         return
44     }
45 
46     fmt.Printf("%s\n", string(data))
47 }
48 
49 func testMap() {
50     var m map[string]interface{}
51     m = make(map[string]interface{})
52     m["username"] = "user1"
53     m["age"] = 18
54     m["sex"] = "man"
55 
56     data, err := json.Marshal(m)
57     if err != nil {
58         fmt.Printf("json.marshal failed, err:", err)
59         return
60     }
61 
62     fmt.Printf("%s\n", string(data))
63 }
64 
65 func testSlice() {
66     var m map[string]interface{}
67     var s []map[string]interface{}
68     m = make(map[string]interface{})
69     m["username"] = "user1"
70     m["age"] = 18
71     m["sex"] = "man"
72 
73     s = append(s, m)
74 
75     m = make(map[string]interface{})
76     m["username"] = "user2"
77     m["age"] = 29
78     m["sex"] = "female"
79     s = append(s, m)
80 
81     data, err := json.Marshal(s)
82     if err != nil {
83         fmt.Printf("json.marshal failed, err:", err)
84         return
85     }
86 
87     //[{"age":18,"sex":"man","username":"user1"},{"age":29,"sex":"female","username":"user2"}]
88     fmt.Printf("%s\n", string(data))
89 }
90 
91 func main() {
92     //testStruct()
93     //testInt()
94     //testMap()
95     testSlice()
96 }
序列化结构体

练习:json序列化map

 1 package main
 2 
 3 import (
 4     "encoding/json"
 5     "fmt"
 6 )
 7 
 8 type User struct {
 9     UserName string `json:"username"`
10     NickName string `json:"nickname"`
11     Age      int
12     Birthday string
13     Sex      string
14     Email    string
15     Phone    string
16 }
17 
18 func testStruct() (ret string, err error) {
19     user1 := &User{
20         UserName: "user1",
21         NickName: "上课看似",
22         Age:      18,
23         Birthday: "2008/8/8",
24         Sex:      "",
25         Email:    "[email protected]",
26         Phone:    "110",
27     }
28 
29     data, err := json.Marshal(user1)
30     if err != nil {
31         err = fmt.Errorf("json.marshal failed, err:", err)
32         return
33     }
34 
35     ret = string(data)
36     return
37 }
38 
39 func testMap() (ret string, err error) {
40     var m map[string]interface{}
41     m = make(map[string]interface{})
42     m["username"] = "user1"
43     m["age"] = 18
44     m["sex"] = "man"
45 
46     data, err := json.Marshal(m)
47     if err != nil {
48         err = fmt.Errorf("json.marshal failed, err:", err)
49         return
50     }
51 
52     ret = string(data)
53     return
54 }
55 
56 func test2() {
57     data, err := testMap()
58     if err != nil {
59         fmt.Println("test map failed, ", err)
60         return
61     }
62 
63     var m map[string]interface{}
64     err = json.Unmarshal([]byte(data), &m)
65     if err != nil {
66         fmt.Println("Unmarshal failed, ", err)
67         return
68     }
69     fmt.Println(m)
70 }
71 
72 func test() {
73     data, err := testStruct()
74     if err != nil {
75         fmt.Println("test struct failed, ", err)
76         return
77     }
78 
79     var user1 User
80     err = json.Unmarshal([]byte(data), &user1)
81     if err != nil {
82         fmt.Println("Unmarshal failed, ", err)
83         return
84     }
85     fmt.Println(user1)
86 }
87 
88 func main() {
89     test()
90     test2()
91 }
序列化map

5. 自定义错误

type error interface { 
     Error() string 
} 
 1 package main
 2 
 3 import (
 4     "errors"
 5     "fmt"
 6 )
 7 
 8 var errNotFound error = errors.New("Not found error")
 9 
10 func main() {
11     fmt.Printf("error: %v", errNotFound)
12 }
example
 1 package main
 2 import (
 3     "fmt"
 4 )
 5 type PathError struct {
 6     Op   string
 7     Path string
 8     Err string
 9 }
10 
11 func (e *PathError) Error() string {
12     return e.Op + " " + e.Path + ": " + e.Err
13 }
14 
15 func test() error {
16     return &PathError{
17         Op:   "op",
18         Path: "path",
19         Err:  "err",
20     }
21 }
22 func main() {
23     if err := test(); err != nil {
24         fmt.Println(err)  //op path: err
25     }
26 }
自定义错误

如何判断自定义错误?

switch err := err.(type) {
    case ParseError:
        PrintParseError(err)
    case PathError:
        PrintPathError(err)
    default: 
... }
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "os"
 6     "time"
 7 )
 8 
 9 type PathError struct {
10     path       string
11     op         string
12     createTime string
13     message    string
14 }
15 
16 func (p *PathError) Error() string {
17     return fmt.Sprintf("path=%s op=%s createTime=%s message=%s", p.path,
18         p.op, p.createTime, p.message)
19 }
20 
21 func Open(filename string) error {
22     file, err := os.Open(filename)
23     if err != nil {
24         return &PathError{
25             path:       filename,
26             op:         "read",
27             message:    err.Error(), //注意这块的Error是系统的error定义的接口Error()
28             createTime: fmt.Sprintf("%v", time.Now()),
29         }
30     }
31 
32     defer file.Close()
33     return nil
34 }
35 
36 func main() {
37     err := Open("C:/sdklflakfljdsafjs.txt")
38     switch v := err.(type) {
39     case *PathError:
40         fmt.Println("get path error,", v) //v.Error() 类似于打印fmt.Println(err),其实内部实现fmt.Println(err.Error())
41     default:
42 
43     }
44 
45 }
自定义错误

Panic&Recover

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func badCall() {
 8     panic("bad end")
 9 }
10 
11 func test() {
12     defer func() {
13         if e := recover(); e != nil { //在这块通过recover捕获panic错误并处理
14             fmt.Printf("Panicking %s\r\n", e)
15         }
16     }()
17 
18     badCall()
19     fmt.Printf("After bad call\r\n")
20 }
21 
22 func main() {
23     fmt.Printf("Calling test\r\n")
24     test()
25     fmt.Printf("Test completed\r\n")
26 }
recover捕获panic错误

课后工作
    实现一个图书管理系统v3,具有以下功能:
     a. 增加持久化存储的功能
     b. 增加日志记录的功能

参考文献:

https://studygolang.com/articles/14669

猜你喜欢

转载自www.cnblogs.com/xuejiale/p/10410183.html