zoukankan      html  css  js  c++  java
  • golang(7):文件读写 & json & 错误处理

    终端读写

    操作终端相关文件句柄常量

    os.Stdin        // 标准输入
    os.Stdout        // 标准输出 (输出到终端)
    os.Stderr        // 标准错误输出 (输出到终端)

    fmt 常见用法

    fmt.Scanln(&firstName, &lastName)                // 从终端读取字符串(以空格分隔)
    fmt.Scanf("%s %s", &firstName, &lastName)        // 作用同 fmt.Scanln(),但 fmt.Scanf() 既能读取字符串也能读取数字
    
    fmt.Printf("Hi %s %s!
    ", firstName, lastName)    // 格式化输出
    fmt.Sscanf(input, format, &f, &i, &s)            // 从字符串中格式化读入(第一个参数表示要读取的字符串,第二个参数表示读取格式,后面的参数表示赋给哪些变量)

    示例代码:

    package main
    
    import "fmt"
    
    type Student struct{
        Name string
        Age int
        Score float64
    }
    
    func main(){
        var s = "stu01 age is 18 score is 95.5"
        var stu Student
        
        fmt.Sscanf(s,"%s age is %d score is %f",&stu.Name,&stu.Age,&stu.Score)    // 变量要传入地址
        fmt.Println(stu)
    }
    
    // 运行结果:
    [root@NEO example01_Sscanf]# go run main/main.go
    {stu01 18 95.5}
    [root@NEO example01_Sscanf]# 

    带缓冲区的读写:

    示例代码1:(从标准输入中读取

    package main
    
    import (
        "bufio"
        "os"
        "fmt"
    )
    
    func main(){
        reader := bufio.NewReader(os.Stdin)        // go 的 struct 没有构造函数,所以 bufio 包中自己写了一个构造函数 NewReader,回一个 Reader实现的指针;bufio.NewReader() 需要传入一个 io.Reader 接口,这个接口中吸有一个 Read() 方法,而 os.Stdin 也实现 Read() 方法,即实现了 io.Reader 这个接口
    
        fmt.Println("pls input:")
        str,err := reader.ReadString('
    ')        // 带缓存区的读取; ReadString() 中的参数是 byte 形式的 分隔符,所以要用 单引号
        if err != nil {
            fmt.Println("read string failed:",err)
            return
        }
    
        fmt.Printf("read string success,str: %s
    ",str)
    }
    
    // 运行结果:
    [root@NEO example02_bufio01]# go run main/main.go
    pls input:
    i am neo
    read string success,str: i am neo
    
    [root@NEO example02_bufio01]# 

    示例代码2:(从文件中读取

    package main
    
    import (
        "fmt"
        "os"
        "bufio"
    )
    
    func main() {
        file,err := os.Open("/root/echotest.txt")    // 读取文件用 os.Open(),写入文件用 os.OpenFile()
        if err != nil {
            fmt.Println("read file failed,",err)
            return 
        }
        defer file.Close()      // 关闭文件
        
        reader := bufio.NewReader(file)            // 把读取的对象 file 作为参数传到 bufio.NewReader() 中
        str,err := reader.ReadString('
    ')        // 以 
     作为分隔符,表示读取一行
        if err != nil {
            fmt.Println("read string failed,",err)
        }
        fmt.Printf("str:%s
    ",str)
    }
    
    // 运行结果:
    [root@NEO main]# go run main.go
    str:hello world neo
    
    [root@NEO main]# 

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

    // 示例代码:
    package main
    
    import (
        "fmt"
        "bufio"
        "os"
        "io"
    )
    
    type CharCount struct {
        ChCount int
        NumCount int
        SpaceCount int
        OtherCount int
    }
    
    func main(){
        file,err := os.Open("/root/go/project/src/go_dev/day07/example02_bufio03_count/main/main.go")
        if err != nil {
            fmt.Println("read file err:",err)
            return
        }
        defer file.Close()
    
        var count CharCount
    
        reader := bufio.NewReader(file)
    
        for {
            str,err := reader.ReadString('
    ')        // 以 
     作为分隔符表示每次读取一行
            if err == io.EOF {    // io.EOF 表示文件读取完后返回的错误(表示文件已经读取完)
                break
            }
    
            if err != nil {
                fmt.Println("read string failed,",err)
                break
            }
    
            runeArr := []rune(str)        // 把 str 字符串转化为 rune 切片
            for _,v := range runeArr{
                switch {
                    case v >= 'a' && v <= 'z':
                        fallthrough
                    case v>= 'A' && v <= 'Z':
                        count.ChCount++
                    case v >= '0' && v <= '9':
                        count.NumCount++
                    case v == ' ' || v == '	':
                        count.SpaceCount++
                    default:
                        count.OtherCount++
                }
            }
        }
        fmt.Printf("ChCount:%d NumCount:%d SpaceCount:%d OtherCount:%d
    ",count.ChCount,count.NumCount,count.SpaceCount,count.OtherCount)
    }
    
    // 运行结果:
    [root@NEO example02_bufio03_count]# go run main/main.go 
    ChCount:598 NumCount:8 SpaceCount:186 OtherCount:290
    [root@NEO example02_bufio03_count]# 
    
    
    // EOF is the error returned by Read when no more input is available.  io.EOF 是文件所有内容读取完后返回的错误 (表示已经把文件读取完了)

    文件读写

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

    读取整个文件示例

    import "io/ioutil"
    buf, err := ioutil.ReadFile(filename string)    // 读取整个文件; buf 是一个字节数组
    err := ioutil.WriteFile(filename string, data []byte, perm os.FileMode)        // 把整个字符串写入文件; perm os.FileMode 表示文件权限

    示例代码:

    package main
    
    import (
        "io/ioutil"
        "fmt"
        "os"
    )
    
    func main() {
        buf, err := ioutil.ReadFile("/root/main.go")    // 读取整个文件;buf 是一个字节数组
        if err != nil {
            fmt.Println(os.Stderr,"Read file err:",err)
            return
        }
    
        fmt.Printf("%s
    ",string(buf))    // 把字节数组转化为字符串
        
        err = ioutil.WriteFile("/root/main_copy.go",buf,0666)
        if err != nil {
            fmt.Printf("write file err:%s
    ",err)
        }
    }
    
    // 运行结果:
    [root@NEO example02_bufio04_ioutil]# go run main/main.go
    package main
    
    import (
        "fmt"
    )
    
    func main(){
        var a *int = new(int)
        var b interface{}
        
        b = a
        fmt.Printf("%v %T %v %T
    ",b,b,*(b.(*int)),b.(*int))
    }
    
    [root@NEO example02_bufio04_ioutil]# 

    读取压缩文件示例

    // 示例代码:
    package main
    
    import (
        "fmt"
        "os"
        "compress/gzip"        // 解压缩文件的包
        "bufio"
    )
    
    func main(){
        fName := "/root/echotest.tar.gz"
        file,err := os.Open(fName)        // file 是文件句柄
        if err != nil {
            fmt.Fprintf(os.Stderr,"Can not open %s, error: %s
    ",fName,err)
            os.Exit(1)
        }
        defer file.Close()
    
        fz,err := gzip.NewReader(file)        // 把文件句柄file 传入 gzip.NewReader();读一部分数据,然后再解压缩,再输出;fz 具有解压缩功能,是 *Reader
    
        if err != nil {
            fmt.Fprintf(os.Stderr,"open gzip failed,err:%v
    ",err)
            return 
        }
    
        reader := bufio.NewReader(fz)    // 让 fz 通过带缓存区的读
        for {
            line, err := reader.ReadString('
    ')
            if err != nil {
                fmt.Println("reading file done")
                os.Exit(0)
            }
            fmt.Println(line)
        }
    }
    
    
    // 运行结果:
    [root@NEO example03_gzip]# go run main/main.go
    echotest.txt0000644000000000000000000000002013521457003012123 0ustar  rootroothello world neo
    
    reading file done
    [root@NEO example03_gzip]# 

    文件写入

    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

    示例代码:

    // 示例代码:
    package main
    
    import (
        "fmt"
        "bufio"
        "os"
    )
    
    func main() {
        outputFile,outputError := os.OpenFile("output.txt",os.O_WRONLY|os.O_CREATE,0666)    // 文件不存在则创建
        if outputError != nil {
            fmt.Println("an error occureed with file creation")
            return
        }
        defer outputFile.Close()
    
        outputWriter := bufio.NewWriter(outputFile)        // 带缓存区的写;传入文件句柄
        for i := 0; i < 5; i++ {
            outputWriter.WriteString("hello world
    ")    // 写入
        }
        outputWriter.Flush()    // 由于是带缓存区的写,所以最后 Flush() 一下,把缓存区的内容从内存刷(写入)到磁盘里面
    }
    
    
    // 运行结果:
    [root@NEO example04_writeFile]# go run main/main.go
    [root@NEO example04_writeFile]# ll
    total 8
    drwxr-xr-x 2 root root 4096 Aug  7 01:19 main
    -rw-r--r-- 1 root root   60 Aug  7 01:19 output.txt
    [root@NEO example04_writeFile]# cat output.txt 
    hello world
    hello world
    hello world
    hello world
    hello world
    [root@NEO example04_writeFile]# 

    拷贝文件

    // 示例代码:
    package main
    
    import (
        "os"
        "io"
        "fmt"
    )
    
    func CopyFile(dstName,srcName string) (written int64, err error){
        // 打开读文件(被拷贝的文件)
        src,err := os.Open(srcName)
        if err != nil {
            return
        }
        defer src.Close()
    
        // 打开写文件(拷贝到哪个文件)
        dst,err := os.OpenFile(dstName,os.O_WRONLY|os.O_CREATE,0644)
        if err != nil {
            return
        }
        defer dst.Close()
    
        return io.Copy(dst,src)        // io.Copy(目的文件句柄,源文件句柄)  --> 拷贝文件
    }
    
    func main(){
        _,err := CopyFile("target.txt","output.txt")
        if err != nil {
            fmt.Println("copy file failed")
            return
        }
        fmt.Println("copy file done")
    }
    
    
    // 运行结果:
    [root@NEO example05_copyFile]# echo "copy file test" > output.txt
    [root@NEO example05_copyFile]# go run main/main.go
    copy file done
    [root@NEO example05_copyFile]# ll
    total 12
    drwxr-xr-x 2 root root 4096 Aug  7 01:38 main
    -rw-r--r-- 1 root root   15 Aug  7 01:39 output.txt
    -rw-r--r-- 1 root root   15 Aug  7 01:39 target.txt
    [root@NEO example05_copyFile]#     

    命令行参数

    os.Args是一个string的切片,用来存储所有的命令行参数        // os.Args 中的每个元素都是字符串;os.Args 的第一个元素是程序本身(路径+程序名)
    flag包的使用,用来解析命令行参数

    原始方式读取命令行参数:os.Args

    // 示例代码:
    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main(){
        fmt.Printf("len of os.Args:%d
    ",len(os.Args))
    
        for i,v := range os.Args {
            fmt.Printf("os.Args[%d]=%s
    ",i,v)
        }
    }
    
    // 编译后的运行结果:
    [root@NEO project]# go build -o bin/example07_osArgs01 go_dev/day07/example07_osArgs01/main
    [root@NEO project]# bin/example07_osArgs01 -c /root/data/
    len of os.Args:3
    os.Args[0]=bin/example07_osArgs01
    os.Args[1]=-c
    os.Args[2]=/root/data/
    [root@NEO project]# 

    flag包的使用,用来解析命令行参数:

    flag.BoolVar(&test, "b", false, "print on newline")        // 第一个参数:用于接收值的一个变量地址;第二个参数表示 key 的名字;第三个参数是 默认值;第四个参数是 使用说明
    flag.StringVar(&str, "s", "", "print on newline")
    flag.IntVar(&count, "c", 1001, "print on newline")

    示例代码:

    package main
    
    import (
        "fmt"
        "flag"
    )
    
    func main(){
        var confPath string
        var logLevel int
        
        flag.StringVar(&confPath,"c","","pls input conf path")
        flag.IntVar(&logLevel,"d",0,"pls input log level")
    
        flag.Parse()    // Parse() 之后 从命令行接收的参数都会生效
        
        fmt.Println("path:",confPath)
        fmt.Println("log level:",logLevel)
    }
    
    
    // 编译后的运行结果:
    [root@NEO project]# go build -o bin/example07_osArgs02 go_dev/day07/example07_osArgs02/main
    [root@NEO project]# bin/example07_osArgs02 -c /root/data/test.conf         // -c 指定 confPath
    path: /root/data/test.conf
    log level: 0        // -d 没指定就用默认的 0
    [root@NEO project]#

    Json数据协议

    1. 导入包:Import “encoding/json”
    2. 序列化: json.Marshal(data interface{}) ([]byte,    error)            // 返回值: 第一个是 字符数组,第二个错误
    3. 反序列化: json.UnMarshal(data []byte,  v  interface{}) error        // 返回值是一个错误 error     

    序列化示例:

    // 示例代码:
    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type User struct{
        UserName string                        // 需要json打包时,struct 中的字段首字母要大写
        NickName string    `json:"nickname"`    // tag 可以改变 json打包时的 key
        Age int
        Sex string
        Email string
    }
    
    func jsonStruct(){
        user := &User{
        UserName:"user01",    
        NickName:"ponyma",
        Age:56,
        Sex:"",
        Email:"110@qq.com",
        }
        
        data,err := json.Marshal(user)
        if err != nil {
            fmt.Printf("json.Marshal failed,err:",err)
            return
        }
    
        fmt.Printf("%s
    ",string(data))        // json.Marshal() 返回的第一个参数是 字符数组 []byte,利用 string()强转为 字符串
    }
    
    func jsonInt(){
        a := 10
        data,err := json.Marshal(a)    
        if err != nil {
            fmt.Printf("json.Marshal failed,err:",err)
            return
        }
        fmt.Printf("%s
    ",string(data))    
    }
    
    func jsonMap(){
        var m map[string]interface{}    // map的value为空接口,可以接收任何类型
        m = make(map[string]interface{})    // 给 map 赋值前要先初始化
        m["name"] = "neo"    
        m["age"] = 18
    
        data,err := json.Marshal(m)    
        if err != nil {
            fmt.Printf("json.Marshal failed,err:",err)
            return
        }
        fmt.Printf("%s
    ",string(data))
    }
    
    func jsonSlice(){
        var slice []map[string]interface{}
    
        var m1 map[string]interface{}
        m1 = make(map[string]interface{})
        m1["id"] = 1
        m1["name"] = "neo01"
        slice = append(slice,m1)
    
        var m2 map[string]interface{}
        m2 = make(map[string]interface{})
        m2["key1"] = "hello"
        m2["key2"] = "world"
        slice = append(slice,m2)
    
        data,err := json.Marshal(slice)
        if err != nil {
            fmt.Printf("json.Marshal failed,err:",err)
            return    
        }
        fmt.Printf("%s
    ",string(data))
        
    }
    
    func main(){
        jsonStruct()    
        jsonInt()
        jsonMap()
        jsonSlice()
    }
    
    // 运行结果:
    [root@NEO example08_json01]# go run main/main.go
    {"UserName":"user01","nickname":"ponyma","Age":56,"Sex":"","Email":"110@qq.com"}
    10
    {"age":18,"name":"neo"}
    [{"id":1,"name":"neo01"},{"key1":"hello","key2":"world"}]
    [root@NEO example08_json01]# 

    反序列化示例:

    // 示例代码:
    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type User struct{
        UserName string                        // 需要json打包时,struct 中的字段首字母要大写
        NickName string    `json:"nickname"`    // tag 可以改变 json打包时的 key
        Age int
        Sex string
        Email string
    }
    
    func jsonStruct() (ret string, err error) {
        user := &User{
        UserName:"user01",    
        NickName:"ponyma",
        Age:56,
        Sex:"",
        Email:"110@qq.com",
        }
        
        data,err := json.Marshal(user)        // 序列化
        if err != nil {
            fmt.Errorf("json.Marshal failed,err:%v
    ",err)    // fmt.Errorf()    --> 错误格式化
            return
        }
        
        ret = string(data)
        return 
    }
    
    func unmarshalStruct(){
        ret,err := jsonStruct()        // ret 是 string 型
        if err != nil {
            fmt.Println("json.Marshal failed,err:",err)
            return
        }
    
        var user User
        err = json.Unmarshal([]byte(ret), &user)    // 反序列化;第一个参数:字节数组;第二个参数:空接口(可接收任何类型)
        if err != nil {
            fmt.Println("json.Unmarshal failed,err:",err)    
            return
        }
        fmt.Printf("ret:%v type:%T
    ",user,user)
    }
    
    func jsonMap() (ret string, err error){
        var m map[string]interface{}    
        m = make(map[string]interface{})
        m["name"] = "neo"    
        m["age"] = 18
    
        data,err := json.Marshal(m)    
        if err != nil {
            fmt.Errorf("json.Marshal failed,err:%v
    ",err)
            return
        }
        
        ret = string(data)
        return
    }
    
    func unmarshalMap(){
        ret,err := jsonMap()    // ret 是 string 型
        if err != nil {
            fmt.Println("json.marshal failed,err:",err)
            return
        }
    
        var m map[string]interface{}
        err = json.Unmarshal([]byte(ret),&m)        // 要改变指向  m 这个 map 指针的指针
        if err != nil {
            fmt.Println("json.unmarshal failed,err:",err)
            return
        }
        fmt.Printf("m:%v type:%T
    ",m,m)
    
    }
    
    func main(){
        unmarshalStruct()
        unmarshalMap()        
    }
    
    
    // 运行结果:
    [root@NEO example08_json02_unmarshal]# go run main/main.go
    ret:{user01 ponyma 56110@qq.com} type:main.User
    m:map[age:18 name:neo] type:map[string]interface {}
    [root@NEO example08_json02_unmarshal]# 

    错误处理

    定义错误

    // 示例代码:
    package main
    
    import (
        "errors"
        "fmt"
    )
    
    var errNotFound error = errors.New("Not found error")        //    自定义错误信息; errNotFound 是 string (用系统自带的 errors.New() 就可以满足大部分需求)
    
    func main() {
        fmt.Printf("error: %v", errNotFound)
    }

    自定义错误:

    // 我们每次返回收到的 error 是一个接口,如下:
    type error interface { 
        Error() string 
    } 

    示例代码:

    // 示例代码1:
    package main
    import (
    //    "fmt"
    )
    type PathError struct {        // 自定义一个错误类型;其实现了 error 接口,所以就可以通过 error 去返回
        Op   string
        Path string
        err string
    }
    func (e *PathError) Error() string {
        return e.Op + " " + e.Path + ": " + e.Err.Error()
    }
    func test() error {
        return &PathError{
            Op:   "op",
            Path: "path",
        }
    }
    func main() {
        test()
    }
    
    
    // 示例代码2:
    package main
    
    import (
        "fmt"
        "os"
        "time"
    )
    
    type PathError struct {        // PathError 是一个自定义错误结构体;PathError 实现了 error 接口,所以 PathError 就可以通过 error 去返回
        path string
        op string
        opTime string
        msg string
    }
    
    func (p *PathError) Error() string{        // 实现 error 接口
        return fmt.Sprintf("path:%s op:%s opTime:%s msg:%s",p.path,p.op,p.opTime,p.msg)
    }
    
    func Open(filename string) error {        // 通过 error 去返回
        file,err := os.Open(filename)
        if err != nil {
            return &PathError{            // 通过 error 去返回
                path:filename,
                op:"read",
                opTime:fmt.Sprintf("%v",time.Now()),
                msg:err.Error(),
            }
        }
    
        defer file.Close()
        return nil        // nil 表示没有错误
    }
    
    func main() {
        err := Open("nvosdanvdsoa.aaatxt")        // 返回的是我们自定义的错误
        if err != nil {
            fmt.Println(err)
            
            v,ok := err.(*PathError)        // 判断是不是我们自定义的错误类型
            if ok {
                fmt.Println("get path error:",v)
            }
        }
    }
    
    
    // 运行结果:
    [root@NEO example09_error01]# go run main/main.go
    path:nvosdanvdsoa.aaatxt op:read opTime:2019-08-08 01:08:22.276422373 +0800 CST m=+0.000517782 msg:open nvosdanvdsoa.aaatxt: no such file or directory
    get path error: path:nvosdanvdsoa.aaatxt op:read opTime:2019-08-08 01:08:22.276422373 +0800 CST m=+0.000517782 msg:open nvosdanvdsoa.aaatxt: no such file or directory
    [root@NEO example09_error01]# 
    
    
    // 判断自定义错误的另一种方法:
    switch err := err.(type) {
        case ParseError:
             PrintParseError(err)
        case PathError:
             PrintPathError(err)
        ... 
        default: 
    } 

    Panic & Recover

    // 示例代码:
    package main
    
    import (
        "fmt"
    )
    
    func badCall() {
        panic("bad end")    // 让程序 panic
    }
    
    func test() {
        defer func() {
            if e := recover(); e != nil {            // 用 recover() 去捕获错误
                fmt.Printf("Panicking %s
    ", e)
            }
        }()
        badCall()
        fmt.Printf("After bad call
    ")
    }
    
    func main() {
        fmt.Printf("Calling test
    ")
        test()
        fmt.Printf("Test completed
    ")
    }
  • 相关阅读:
    Redis主从复制
    POI导出给指定单元格添加背景色
    Mybatis的resultMap使用
    前后端分离
    日常总结
    java环境变量配置
    Java线程池七个参数详解
    java中常见的锁
    Linux定时任务
    SQL语句的整理
  • 原文地址:https://www.cnblogs.com/neozheng/p/11297027.html
Copyright © 2011-2022 走看看