内容简介:操作终端相关文件句柄常量:这个是fmt包里的一个方法,打印到文件。比平时用的fmt打印多一个参数,这个参数接收的就是文件句柄,一个实现了把终端的标准输出的文件句柄传入,就是打印到标准输出,即屏幕:
终端读写
操作终端相关文件句柄常量:
os.Stdin os.Stdout os.Stderr
这个是fmt包里的一个方法,打印到文件。比平时用的fmt打印多一个参数,这个参数接收的就是文件句柄,一个实现了 io.Winter
的接口:
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
把终端的标准输出的文件句柄传入,就是打印到标准输出,即屏幕:
package main import ( "os" "fmt" ) func main(){ fmt.Fprintln(os.Stdout, "TEST") }
终端输入
先打印提示信息,然后获取用户输入的值,最后打印出来:
package main import "fmt" var firstName, lastName string func main(){ fmt.Print("Please enter your full name:") fmt.Scanln(&firstName, &lastName) // fmt.Scanf("%s %s", &firstName, &lastName) // 和上面那句效果一样 fmt.Printf("Hi %s %s.\n", firstName, lastName) }
把字符串作为格式的化输入
使用 fmt 包里的 Sscanf()方法:
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
Scanf 扫描实参 string,并将连续由空格分隔的值存储为连续的实参, 其格式由 format 决定。它返回成功解析的条目数。
不是很好理解的话,参考下下面的例子:
package main import "fmt" func main(){ var ( input = "12.34 567 Golang" // 要扫描的字符串 format = "%f %d %s" // 每段字符串的格式 i float32 // 对应格式的变量,把字符串里的每一段赋值到这些变量里 j int k string ) fmt.Sscanf(input, format, &i, &j, &k) fmt.Println(i) fmt.Println(j) fmt.Println(k) }
带缓冲区的读写
不直接操作 io,在缓冲区里进行读写,io的操作交由操作系统处理,主要是解决性能的问题。
这里要使用 bufio 包,下面是缓冲区进行读操作的示例:
package main import ( "bufio" "fmt" "os" ) func main() { var inputReader *bufio.Reader // bufio包里的一个结构体类型 // 给上面的结构体赋值,包里提供了构造函数 inputReader = bufio.NewReader(os.Stdin) // 生成实例,之后要调用里面的方法 fmt.Print("请随意输入内容: ") // 调用实例的方法进行读操作,就是带缓冲区的操作了 input, err := inputReader.ReadString('\n') // 这里是字符类型 if err == nil { fmt.Println(input) } }
上面是从终端读取,文件读写下面会讲,先来个从文件读取的示例:
package main import ( "bufio" "fmt" "os" "strings" "io" ) func main() { file, err := os.Open("test.txt") if err != nil { fmt.Println("ERROR:", err) return } defer file.Close() // 函数返回时关闭文件 bufReader := bufio.NewReader(file) for { line, err := bufReader.ReadString('\n') // 最后一行会同时返回 line 和 err,所以先打印 fmt.Println(strings.TrimSpace(line)) if err != nil { if err == io.EOF { fmt.Println("读取完毕") break } else { fmt.Println("读取文件错误:", err) return } } } }
文件读写
os.File 是个结构体,封装了所有文件相关的操作。之前讲的 os.Stdin、os.Stdout、os.Stderr 都是文件句柄,都是 *os.File
读取整个文件
"io/ioutil" 可以直接把整个文件读取出来,适合文件不是很大的情况:
package main import ( "fmt" "io/ioutil" ) func main() { buf, err := ioutil.ReadFile("test.txt") if err != nil { fmt.Println("ERROR", err) return } fmt.Println(string(buf)) // buf是[]byte类型,要转字符串 // 写操作 err = ioutil.WriteFile("wtest.txt", buf, 0x64) if err != nil { panic(err.Error()) } }
上面还有整个文件写入的操作。
读取压缩文件
下面的代码是解压读取一个 .gz 文件,注意不是 .tar.gz 。打了tar包应该是不行的:
package main import ( "compress/gzip" "os" "fmt" "bufio" "io" "strings" ) func main() { fileName := "test.gz" var reader *bufio.Reader file, err := os.Open(fileName) if err != nil { fmt.Println("Open ERROE:", err) os.Exit(1) } defer file.Close() // 记得关文件 gzFile, err := gzip.NewReader(file) if err != nil { fmt.Println("gz ERROR:", err) return } reader = bufio.NewReader(gzFile) for { line, err := reader.ReadString('\n') fmt.Println(strings.TrimSpace(line)) if err != nil { if err == io.EOF { fmt.Println("读取完毕") break } else { fmt.Println("Read ERROR:", err) os.Exit(0) } } } }
文件写入
写入文件的命令:
os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
第二个参数是文件打开模式:
- os.O_WRONLY : 只写
- os.O_CREATE : 创建文件
- os.O_RDONLY : 只读
- os.O_RDWR : 读写
- os.O_TRUNC : 清空
第三个参数是权限控制,同 Linux 的ugo权限。
文件写入的示例:
package main import ( "bufio" "fmt" "os" "strconv" ) func main() { outputFile, err := os.OpenFile("test.txt", os.O_WRONLY|os.O_CREATE, 0666) if err != nil { fmt.Println("ERROR", err) return } defer outputFile.Close() outputWriter := bufio.NewWriter(outputFile) outputString := "Hello World! " for i := 0; i < 10; i++ { outputWriter.WriteString(outputString + strconv.Itoa(i) + "\n") } outputWriter.Flush() // 强制刷新,保存到磁盘 }
拷贝文件
首先分别打开2个文件,然后拷贝文件只要一次调用传入2个文件句柄就完成了:
package main import ( "io" "fmt" "os" ) func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { fmt.Println("Open ERROR", err) return } defer src.Close() dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { fmt.Println("OpenFile ERROR", err) return } defer dst.Close() // 先依次把2个文件都打开,然后拷贝只要下面这一句 return io.Copy(dst, src) } func main() { CopyFile("test_copy.txt", "test.txt") fmt.Println("文件拷贝完成") }
命令行参数
os.Args 是一个 string 的切片,用来存储所有的命令行参数。
package main import ( "os" "fmt" ) func main() { fmt.Println(len(os.Args)) for i, v := range os.Args { fmt.Println(i, v) } } /* 执行结果 PS H:\Go\src\go_dev\day7\args\beginning> go run main.go arg1 arg2 arg3 4 0 [省略敏感信息]\main.exe 1 arg1 2 arg2 3 arg3 PS H:\Go\src\go_dev\day7\args\beginning> */
os.Args 至少有一个元素,如果一个参数也不打,第一个元素就是命令本身。之后的命令行参数从下标1开始存储。
解析命令行参数
flag 包实现命令行标签解析。
func BoolVar(p *bool, name string, value bool, usage string) func StringVar(p *string, name string, value string, usage string) func IntVar(p *int, name string, value int, usage string)
第一个参数是个指针,指向要接收的参数的值
第二个参数是指定的名字
第三个参数是默认值
第四个参数是用法说明
用法示例:
package main import ( "fmt" "flag" ) func main() { var ( enable bool conf string num int ) flag.BoolVar(&enable, "b", false, "是否启用") flag.StringVar(&conf, "s", "test.conf", "配置文件") flag.IntVar(&num, "i", 0, "数量") flag.Parse() // 读取命令行参数进行解析 fmt.Println(enable, conf, num) } /* 执行结果 PS H:\Go\src\go_dev\day7\args\flag_var> go run main.go false test.conf 0 PS H:\Go\src\go_dev\day7\args\flag_var> go run main.go -b -s default.conf -i 10 true default.conf 10 PS H:\Go\src\go_dev\day7\args\flag_var> */
Json数据协议
导入包
import "encoding/json"
序列化
json.Marshal(data interface{})
示例:
package main import ( "encoding/json" "fmt" ) type User struct { UserName string `json:"username"` NickName string `json:"nickname"` Age int `json:"age"` Vip bool `json:"vip"` } func main() { u1 := &User{ UserName: "Sara", NickName: "White Canary", Age: 29, Vip: true, } if data, err := json.Marshal(u1); err == nil{ fmt.Println(string(data)) } }
反序列化
json.Unmarshal(data []byte, v interface{})
示例:
package main import ( "encoding/json" "fmt" ) type User struct { UserName string `json:"username"` NickName string `json:"nickname"` Age int `json:"age"` Vip bool `json:"vip"` } func main() { var jsonStr = `{ "username": "Kara", "nickname": "Supergirl", "age": 20, "vip": false }` var jsonByte = []byte(jsonStr) var u2 User if err := json.Unmarshal(jsonByte, &u2); err == nil { fmt.Println(u2) } else { fmt.Println("ERROR:", err) } }
错误处理
error 类型是在 builtin 包里定义的。error 是个接口,里面实现了一个 Error() 的方法,返回一个字符串:
type error interface { Error() string }
所以其实 error 也就是个字符串信息。
定义错误
error 包实现了用于错误处理的函数。
New 返回一个按给定文本格式化的错误:
package main import ( "errors" "fmt" ) var errNotFound error = errors.New("Not found error") func main() { fmt.Println("ERROR:", errNotFound) }
平时简单这样用用就可以了,也很方便。不过学习嘛,下面稍微再深入点。
自定义错误
主要是学习,上面的 New() 函数用起来更加方便。
使用自定义错误返回:
package main import ( "fmt" "os" ) type PathError struct { Op string Path string err string // 把这个信息隐藏起来,所以是小写 } // 实现error的接口 func (e *PathError) Error() string { return e.Op + " " + e.Path + " 路径不存在\n原始错误信息: " + e.err } func Open(filename string) error { file, err := os.Open(filename) if err != nil { return &PathError{ Op: "read", Path: filename, err: err.Error(), } } defer file.Close() return nil } func main() { err := Open("test.txt") if err != nil { fmt.Println(err) } } /* 执行结果 PS H:\Go\src\go_dev\day7\error\diy_error> go run main.go read test.txt 路径不存在 原始错误信息: open test.txt: The system cannot find the file specified. PS H:\Go\src\go_dev\day7\error\diy_error> */
判断自定义错误
这里用 switch 来判断:
switch err := err.(type) { case ParseError: PrintParseError(err) case.PathError: PrintPathError(err) default: fmt.Println(err) }
异常和捕捉
首先调用 panic 来抛出异常:
package main func badCall() { panic("bad end") } func main() { badCall() } /* 执行结果 PS H:\Go\src\go_dev\day7\error\panic> go run main.go panic: bad end goroutine 1 [running]: main.badCall() H:/Go/src/go_dev/day7/error/panic/main.go:4 +0x40 main.main() H:/Go/src/go_dev/day7/error/panic/main.go:8 +0x27 exit status 2 PS H:\Go\src\go_dev\day7\error\panic> */
执行后就抛出异常了,但是这样程序也崩溃了。
下面来捕获异常,go里没有try之类来捕获异常,所以panic了就是真的异常了,但是还不会马上就崩溃。panic的函数并不会立刻返回,而是先defer,再返回。如果有办法将panic捕获到,并阻止panic传递,就正常处理,如果没有没有捕获,程序直接异常终止。 这里并不是像别的语言里那样捕获异常,因为即使捕获到了,也只是执行defer,之后还是要异常终止的,而不是继续在错误的点往下执行。
注意:就像上面说的,在 go 里panic了就是真的异常了。recover之后,逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回。
下面是使用 defer 处理异常的示例:
package main import "fmt" func badCall() { panic("bad end") } func test() { // 用defer在最后捕获异常 defer func() { if e := recover(); e != nil { fmt.Println("Panic", e) } }() badCall() } func main() { test() }
所以像 python 里的 try except 那样捕获异常,在go里,大概就是返回个 err(error类型) ,然后判断一下 err 是不是 nil。
课后作业
实现一个图书管理系统v3,增加一下功能:
- 增加持久化存储的功能
- 增加日志记录的功能
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
- 计算机语言发展的三个阶段:机器语言、汇编语言与高级语言
- 凹 (“Wa”) 语言:可以嵌入 Go 语言环境的脚本语言
- Rust语言恰巧是一门解决了Go语言所有问题的语言
- 获取系统语言/当前 App支持语言
- 【Go 语言教程】Go 语言简介
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
区块链与人工智能:数字经济新时代
高航、俞学劢、王毛路 / 电子工业出版社 / 2018-7-23 / 80
《区块链与人工智能》是畅销书《区块链与新经济:数字货币2.0时代》全新修订升级版。本书是市场上为数不多的系统阐述区块链、人工智能技术与产业的入门级系统教程。从比特币到各类数字货币(代币),从基础原理到应用探讨,全景式呈现区块链与人工智能的发展脉络,既有历史的厚重感也有科技的未来感。本书的另一个亮点是系统整理了区块链创业地图,是一本关于区块链创业、应用、媒体的学习指南,以太坊创始人Vitalik专门......一起来看看 《区块链与人工智能:数字经济新时代》 这本书的介绍吧!