Go语言学习之7 接口实例、终端文件读写、异常处理
本节主要内容:
1. 终端读写
2. 文件读写
3. 命令行参数
4. Json
5. 自定义错误
1. 终端读写
操作终端相关文件句柄常量
os.Stdin:标准输入
os.Stdout:标准输出
os.Stderr:标准错误输出
- package main
- import (
- "fmt"
- )
- var (
- firstName, lastName, s string
- i int
- f float32
- input = "56.12 / 5212 / Go"
- format = "%f / %d / %s"
- )
- func main() {
- fmt.Println("Please enter your full name: ") //Chris Naegels
- fmt.Scanln(&firstName, &lastName) //和下面等价
- // fmt.Scanf("%s %s", &firstName, &lastName)
- fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels!
- fmt.Sscanf(input, format, &f, &i, &s)
- fmt.Println("From the string we read: ", f, i, s) //From the string we read: 56.12 5212 Go
- }
example
- package main
- import (
- "bufio"
- "fmt"
- "os"
- )
- func main() {
- fmt.Println("Input string >>")
- reader := bufio.NewReader(os.Stdin)
- res, err := reader.ReadString('\n')
- if err != nil {
- fmt.Println("Read failed, Error: ", err)
- }
- fmt.Printf("Read success, content: ", res)
- }
从终端读入
- package main
- import (
- "fmt"
- "os"
- "bufio"
- )
- func main() {
- // fmt.Fprintf(os.Stdout, "%s\n", "hello world")
- buf := bufio.NewWriter(os.Stdout)
- fmt.Fprintf(buf, "%s\n", "hello world")
- buf.Flush()
- }
带缓冲区的终端读写
2. 文件读写
(1)文件读取
bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。
实际上在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据;只有当缓冲区没有数据 时,才会从数据源获取数据更新缓冲。
- package main
- import (
- "os"
- "fmt"
- "bufio"
- )
- func main() {
- var input *bufio.Reader
- var str string
- var err error
- input = bufio.NewReader(os.Stdin)
- str, err = input.ReadString('\n') //注意:ReadString会返回读取的字符串(包括分隔符'\n')
- if err != nil {
- fmt.Println("Read failed")
- }
- fmt.Println("Read success, content: ", str)
- }
example
练习: 从终端读取一行字符串,统计英文、数字、空格以及其他字符的数量。
- package main
- import (
- "fmt"
- "os"
- "bufio"
- "strings"
- )
- type CharCount struct {
- ChCount int
- NumCount int
- SpaceCount int
- OtherCount int
- }
- func Count(str string, cc *CharCount) {
- runeArr := []rune(str)
- for _, v := range runeArr {
- fmt.Printf("--%v\n",v)
- switch {
- case v >= 'A' && v <= 'Z':
- fallthrough
- case v >= 'a' && v <= 'z':
- cc.ChCount++
- case v >= '' && v <= '':
- cc.NumCount++
- case v == ' ':
- cc.SpaceCount++
- default:
- cc.OtherCount++
- }
- }
- }
- func main() {
- var cc CharCount
- fmt.Println("Input string >>")
- reader := bufio.NewReader(os.Stdin)
- str, err := reader.ReadString('\n')
- if err != nil {
- fmt.Println("Read failed")
- }
- str = strings.Trim(string(str), "\r\n") //去掉末尾的\r\n,否则OtherCount会多加2
- Count(string(str), &cc)
- fmt.Println(cc)
- }
从terminal读取
os.File封装所有文件相关操作,之前讲的 os.Stdin,os.Stdout, os.Stderr都是*os.File
a. 打开一个文件进行读操作: os.Open(name string) (*File, error)
b. 关闭一个文件:File.Close()
1)将整个文件读取到内存
- package main
- import (
- "fmt"
- "io/ioutil"
- )
- func main() {
- fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
- data, err := ioutil.ReadFile(fileName)
- if err != nil {
- fmt.Println("File reading error", err)
- return
- }
- fmt.Println("Contents of file: ", string(data))
- }
读取整个文件
2)分块读取文件
在前面的章节,我们学习了如何把整个文件读取到内存。当文件非常大时,尤其在 RAM 存储量不足的情况下,把整个文件都读入内存是没有意义的。更好的方法是分块读取文件。这可以使用 bufio 包来完成。
- package main
- import (
- "bufio"
- "fmt"
- "log"
- "os"
- "io"
- )
- func EmptyArray(arr []byte) {
- for i := ; i < len(arr); i++ {
- arr[i] =
- }
- }
- func main() {
- fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
- f, err := os.Open(fileName)
- if err != nil {
- log.Fatal(err)
- }
- defer func() {
- if err = f.Close(); err != nil {
- log.Fatal(err)
- }
- }()
- var str string
- r := bufio.NewReader(f)
- b := make([]byte, ) //每次读取3个字节
- for {
- EmptyArray(b)
- _, err := r.Read(b)
- if err == io.EOF {
- fmt.Println("Read finish")
- break
- }
- if err != nil {
- fmt.Println("Error reading file: ", err)
- break
- }
- str = string(b)
- fmt.Printf("%s", str)
- }
- }
分块读取
3)逐行读取文件
- package main
- import (
- "bufio"
- "fmt"
- "log"
- "os"
- )
- func main() {
- fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.txt"
- f, err := os.Open(fileName)
- if err != nil {
- log.Fatal(err)
- }
- defer func() {
- if err = f.Close(); err != nil {
- log.Fatal(err)
- }
- }()
- s := bufio.NewScanner(f)
- for s.Scan() {
- fmt.Println(s.Text())
- }
- if err = s.Err(); err != nil {
- log.Fatal(err)
- }
- }
逐行读取
练习:读取压缩文件(zip)
- package main
- // 引入所需包
- import (
- "os"
- "compress/gzip"
- "io/ioutil"
- "fmt"
- )
- // gzip文件
- func main() {
- fileName := "F:\\Go\\project\\src\\go_dev\\day7\\test.zip"
- // 打开本地gz格式压缩包
- fr, err := os.Open(fileName)
- if err != nil {
- panic(err)
- } else {
- println("open file success!")
- }
- // defer: 在函数退出时,执行关闭文件
- defer fr.Close()
- // 创建gzip文件读取对象
- gr, err := gzip.NewReader(fr)
- if err != nil {
- panic(err)
- }
- // defer: 在函数退出时,执行关闭gzip对象
- defer gr.Close()
- // 读取gzip对象内容
- rBuf, err := ioutil.ReadAll(gr)
- if err != nil {
- fmt.Println("[read gzip data err]: ", err)
- }
- // 以文本形式输出
- fmt.Printf("%s\n", rBuf)
- }
读取压缩文件示例
(2)文件写入
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 :清空
- 第三个参数:权限控制:
- r ——>
- w ——>
- x ——>
- package main
- import (
- "fmt"
- "os"
- "bufio"
- )
- func main() {
- filePath := "F:\\Go\\project\\src\\go_dev\\day7\\write_test.txt"
- outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, )
- if err != nil {
- fmt.Println("Failed to write file")
- return
- }
- defer outFile.Close()
- outWrite := bufio.NewWriter(outFile)
- des := "hello world!\n"
- for i := ; i < ; i++ {
- outWrite.WriteString(des)
- }
- outWrite.Flush()
- }
example
(3)拷贝文件
- package main
- import (
- "fmt"
- "os"
- "io"
- )
- //A successful Copy returns err == nil, not err == EOF
- func CopyFile(destName, srcName string) (written int64, err error) {
- src, err := os.Open(srcName)
- if err != nil {
- panic(err)
- }
- defer src.Close()
- dest, err := os.OpenFile(destName, os.O_WRONLY|os.O_CREATE, )
- if err != nil {
- panic(err)
- }
- defer dest.Close()
- return io.Copy(dest, src)
- }
- func main() {
- srcName := "F:\\Go\\project\\src\\go_dev\\day7\\write_test.txt"
- destName := "F:\\Go\\project\\src\\go_dev\\day7\\dest_test.txt"
- wByte, err := CopyFile(destName, srcName)
- if err != nil {
- fmt.Println("Copy failed")
- } else {
- fmt.Printf("Copy %d byte from src to dest\n", wByte)
- }
- }
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", , "print on newline")
- package main
- import (
- "fmt"
- "os"
- )
- func main() {
- fmt.Printf("len of args:%d\n", len(os.Args))
- for i, v := range os.Args {
- fmt.Printf("args[%d]=%s\n", i, v)
- }
- }
- //输入:
- //go run main7.go hello world
- // 输出:
- // len of args:3
- // args[0]=C:\Users\ADMINI~1\AppData\Local\Temp\go-build596136718\command-line-argu
- // ments\_obj\exe\main7.exe
- // args[1]=hello
- // args[2]=world
example
- package main
- import (
- "fmt"
- "flag"
- )
- func main() {
- var configPath string
- var logLevel int
- flag.StringVar(&configPath, "c", "", "Please config path")
- flag.IntVar(&logLevel, "d", , "Please log level")
- flag.Parse()
- fmt.Println("configPath: ", configPath)
- fmt.Println("logLevel: ", logLevel)
- }
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序列化结构体
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type User struct {
- UserName string `json:"username"`
- NickName string `json:"nickname"`
- Age int
- Birthday string
- Sex string
- Email string
- Phone string
- }
- func testStruct() {
- user1 := &User{
- UserName: "user1",
- NickName: "上课看似",
- Age: ,
- Birthday: "2008/8/8",
- Sex: "男",
- Email: "mahuateng@qq.com",
- Phone: "",
- }
- data, err := json.Marshal(user1)
- if err != nil {
- fmt.Printf("json.marshal failed, err:", err)
- return
- }
- fmt.Printf("%s\n", string(data))
- }
- func testInt() {
- var age =
- data, err := json.Marshal(age)
- if err != nil {
- fmt.Printf("json.marshal failed, err:", err)
- return
- }
- fmt.Printf("%s\n", string(data))
- }
- func testMap() {
- var m map[string]interface{}
- m = make(map[string]interface{})
- m["username"] = "user1"
- m["age"] =
- m["sex"] = "man"
- data, err := json.Marshal(m)
- if err != nil {
- fmt.Printf("json.marshal failed, err:", err)
- return
- }
- fmt.Printf("%s\n", string(data))
- }
- func testSlice() {
- var m map[string]interface{}
- var s []map[string]interface{}
- m = make(map[string]interface{})
- m["username"] = "user1"
- m["age"] =
- m["sex"] = "man"
- s = append(s, m)
- m = make(map[string]interface{})
- m["username"] = "user2"
- m["age"] =
- m["sex"] = "female"
- s = append(s, m)
- data, err := json.Marshal(s)
- if err != nil {
- fmt.Printf("json.marshal failed, err:", err)
- return
- }
- //[{"age":18,"sex":"man","username":"user1"},{"age":29,"sex":"female","username":"user2"}]
- fmt.Printf("%s\n", string(data))
- }
- func main() {
- //testStruct()
- //testInt()
- //testMap()
- testSlice()
- }
序列化结构体
练习:json序列化map
- package main
- import (
- "encoding/json"
- "fmt"
- )
- type User struct {
- UserName string `json:"username"`
- NickName string `json:"nickname"`
- Age int
- Birthday string
- Sex string
- Email string
- Phone string
- }
- func testStruct() (ret string, err error) {
- user1 := &User{
- UserName: "user1",
- NickName: "上课看似",
- Age: ,
- Birthday: "2008/8/8",
- Sex: "男",
- Email: "mahuateng@qq.com",
- Phone: "",
- }
- data, err := json.Marshal(user1)
- if err != nil {
- err = fmt.Errorf("json.marshal failed, err:", err)
- return
- }
- ret = string(data)
- return
- }
- func testMap() (ret string, err error) {
- var m map[string]interface{}
- m = make(map[string]interface{})
- m["username"] = "user1"
- m["age"] =
- m["sex"] = "man"
- data, err := json.Marshal(m)
- if err != nil {
- err = fmt.Errorf("json.marshal failed, err:", err)
- return
- }
- ret = string(data)
- return
- }
- func test2() {
- data, err := testMap()
- if err != nil {
- fmt.Println("test map failed, ", err)
- return
- }
- var m map[string]interface{}
- err = json.Unmarshal([]byte(data), &m)
- if err != nil {
- fmt.Println("Unmarshal failed, ", err)
- return
- }
- fmt.Println(m)
- }
- func test() {
- data, err := testStruct()
- if err != nil {
- fmt.Println("test struct failed, ", err)
- return
- }
- var user1 User
- err = json.Unmarshal([]byte(data), &user1)
- if err != nil {
- fmt.Println("Unmarshal failed, ", err)
- return
- }
- fmt.Println(user1)
- }
- func main() {
- test()
- test2()
- }
序列化map
5. 自定义错误
- type error interface {
- Error() string
- }
- package main
- import (
- "errors"
- "fmt"
- )
- var errNotFound error = errors.New("Not found error")
- func main() {
- fmt.Printf("error: %v", errNotFound)
- }
example
- package main
- import (
- "fmt"
- )
- type PathError struct {
- Op string
- Path string
- Err string
- }
- func (e *PathError) Error() string {
- return e.Op + " " + e.Path + ": " + e.Err
- }
- func test() error {
- return &PathError{
- Op: "op",
- Path: "path",
- Err: "err",
- }
- }
- func main() {
- if err := test(); err != nil {
- fmt.Println(err) //op path: err
- }
- }
自定义错误
如何判断自定义错误?
- switch err := err.(type) {
- case ParseError:
- PrintParseError(err)
- case PathError:
- PrintPathError(err)
- default:
...- }
- package main
- import (
- "fmt"
- "os"
- "time"
- )
- type PathError struct {
- path string
- op string
- createTime string
- message string
- }
- func (p *PathError) Error() string {
- return fmt.Sprintf("path=%s op=%s createTime=%s message=%s", p.path,
- p.op, p.createTime, p.message)
- }
- func Open(filename string) error {
- file, err := os.Open(filename)
- if err != nil {
- return &PathError{
- path: filename,
- op: "read",
- message: err.Error(), //注意这块的Error是系统的error定义的接口Error()
- createTime: fmt.Sprintf("%v", time.Now()),
- }
- }
- defer file.Close()
- return nil
- }
- func main() {
- err := Open("C:/sdklflakfljdsafjs.txt")
- switch v := err.(type) {
- case *PathError:
- fmt.Println("get path error,", v) //v.Error() 类似于打印fmt.Println(err),其实内部实现fmt.Println(err.Error())
- default:
- }
- }
自定义错误
Panic&Recover
- package main
- import (
- "fmt"
- )
- func badCall() {
- panic("bad end")
- }
- func test() {
- defer func() {
- if e := recover(); e != nil { //在这块通过recover捕获panic错误并处理
- fmt.Printf("Panicking %s\r\n", e)
- }
- }()
- badCall()
- fmt.Printf("After bad call\r\n")
- }
- func main() {
- fmt.Printf("Calling test\r\n")
- test()
- fmt.Printf("Test completed\r\n")
- }
recover捕获panic错误
图书管理系统v3:
实现一个图书管理系统v3,具有以下功能:
a. 增加持久化存储的功能
b. 增加日志记录的功能
参考文献:
- https://studygolang.com/articles/14669
Go语言学习之7 接口实例、终端文件读写、异常处理的更多相关文章
- 51单片机C语言学习笔记7:关于.c文件和.h文件
1)h文件作用 1 方便开发:包含一些文件需要的共同的常量,结构,类型定义,函数,变量申明: 2 提供接口:对一个软件包来说可以提供一个给外界的接口(例如: stdio.h). 2)h文件里应该有什么 ...
- Python学习(九)IO 编程 —— 文件读写
Python 文件读写 Python内置了读写文件的函数,用法和C是兼容的.本节介绍内容大致有:文件的打开/关闭.文件对象.文件的读写等. 本章节仅示例介绍 TXT 类型文档的读写,也就是最基础的文件 ...
- android菜鸟学习笔记17----Android数据存储(一)文件读写
假如有如下需求,要求能够记录用户输入的用户名和密码,下次登录时,能直接获取之前保存的用户名密码,并在相应的EditText中显示. 要保存用户输入的数据,最先想到的应该就是文件读写了. 通过对andr ...
- 【python系统学习17】python中的文件读写
python中的文件读写 文件读写,是Python代码调用电脑文件的主要功能,能被用于读取和写入文本.音频片段.Excel文档.邮件以及任何保存在电脑上的东西. 可使用python批量的操作本地文件, ...
- Go语言学习笔记(9)——接口类型
接口 Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口. /* 定义接口 */ type interface_name in ...
- 吴裕雄--天生自然C++语言学习笔记:C++ 实例
C++ 实例 - 输出 "Hello, World!" #include <iostream> using namespace std; int main() { co ...
- AT&T汇编语言学习:利用c库、文件读写
AT&T汇编.调用C库函数.读/写文件 d0321:更新读文件代码(图片)以后会更新代码版. d0329:汇编文本读取.简单动画. ============================== ...
- 【原创】go语言学习(十六)接口
目录 接口介绍与定义 空接口和类型断言 指针接收和值接收区别 接口嵌套 接口介绍与定义 1. 接口定义了一个对象的行为规范 A. 只定义规范,不实现B. 具体的对象需要实现规范的细节 2.Go中接口定 ...
- python学习笔记:接口开发——flask Demo实例
举例1,返回当前时间接口 ''' 初始化:所有的Flask都必须创建程序实例, web服务器使用wsgi协议,把客户端所有的请求都转发给这个程序实例 程序实例是Flask的对象,一般情况下用如下方法实 ...
随机推荐
- k8s tensorflow
Online learning github source Kubeflow实战系列 Prepare 了解ksonnet初探Google之Kubeflow (采用的是0.8.0)install dep ...
- windows安装 php-redis redis 扩展
1.查看phpinfo(),确定要下载的扩展版本,扩展的下载地址在:https://pecl.php.net/package/redis 上图对应是是以下版本 2.把下载包里的文件放到php的ext文 ...
- Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) Problem A - B
Pronlem A In a small restaurant there are a tables for one person and b tables for two persons. It i ...
- ant____<project>标签的使用与含义
<project> 标记项目,例如: <project name = "java-ant project" default = "run"&g ...
- 第三章 Web页面建设
认识<q>元素: 简短的引用. 问:你去掉了双引号,换成了一个<q>元素,只是为了显示双引号?这样不是更复杂了吗? 答:不.在增加<q>元素之前,浏览器只知道这是一 ...
- UVALive 7503 Change(乱搞)题解
题意:你现在有面额为A的纸币,现在需要面额为B的钱(可以是一张也可以是好多张拼成一张),有一台自动售货机,里面有任意价格的商品,售货机兑换出的零钱是随机的(比如找你0.03可能给你0.01+0.01+ ...
- 题解——HDU 1848 Fibonacci again and again
一道组合游戏的题目 SG函数的板子题 预处理出SG函数的值然后回答询问即可 代码 #include <cstdio> #include <algorithm> #include ...
- (zhuan) 自然语言处理中的Attention Model:是什么及为什么
自然语言处理中的Attention Model:是什么及为什么 2017-07-13 张俊林 待字闺中 要是关注深度学习在自然语言处理方面的研究进展,我相信你一定听说过Attention Model( ...
- codeforce gym/100495/problem/F Snake++——DFS应用
emmmm.... 在被新生暴打后,我花了很久才补出这道DFS.由于WA1检查了半天,最后竟然是输出少了一个: ,心态小崩. 这里普通的dfs算出的连通区域并不能直接当做最后的答案.所以需要类似模 ...
- tcpdump使用方法
TcpDump可以将网络中传送的数据包完全截获下来提供分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.not等逻辑语句来帮助你去掉无用的信息. 工作中使用tcpdump命令抓 ...