Go入门系列

Go入门系列(六)I/O

2020-03-16  本文已影响0人  RabbitMask

目录:
一、终端I/O
二、文件I/O

一、终端I/O

Go语言的终端I/O操作在基础包上有封装了多种,我们以fmt包为例:
如果为单次输入,可使用Scanln,如一次输入多个变量,可使用Scanf

func main()  {
    var name string
    var age int
    fmt.Print("请输入姓名:")
    _, _ = fmt.Scanln(&name)
    fmt.Print("请输入年龄:")
    _, _ = fmt.Scanln(&age)
    fmt.Printf("您的姓名为:%s,您的年龄为:%d",name,age)
}
#输出
请输入姓名:rabbit
请输入年龄:18
您的姓名为:rabbit,您的年龄为:18

大家可能注意到与网上常见的教程不一样,这里使用了两个忽略符:_, _,可以简单理解为赋值但以后不再使用,因为Go语言是不允许声明却不使用的,这属于语法错误,当然,这里也可以不加,本教程刻意而为之只是想做个提醒。
我们查看ScanforScanln方法可以看到,实际上这两个方法是存在返回值的:

func Scanln(a ...interface{}) (n int, err error) {
    return Fscanln(os.Stdin, a...)
}

我们接下来以Scanf为例启用返回值:

func main()  {
    var name string
    var age int
    fmt.Print("请输入姓名和年龄:")
    _, err := fmt.Scanf("%s %d",&name,&age)
    if err != nil{
        println(err.Error())
    }else {
        fmt.Printf("您的姓名为:%s,您的年龄为:%d",name,age)
    }
}
#输出
请输入姓名和年龄:rabbit 18
您的姓名为:rabbit,您的年龄为:18

如错误输入,打印报错:

请输入姓名和年龄:rabbit rabbit
expected integer

顺便来探讨下,如果跟其它教材一样不启用错误处理会怎么样呢?

func main()  {
    var name string
    var age int·
    fmt.Print("请输入姓名和年龄:")
    fmt.Scanf("%s %d",&name,&age)
    fmt.Printf("您的姓名为:%s,您的年龄为:%d",name,age)
}
#输出
请输入姓名和年龄:rabbit rabbit
您的姓名为:rabbit,您的年龄为:0

关于输出前面基本涉及了,简单总结一下fmt包中常用的三个方法:
Println :可以打印出字符串,和变量
Printf : 只可以打印出格式化的字符串,可以输出字符串类型的变量,不可以输出整形变量和整形
Print:效果同Println,但没有自动换行,需手动增加\n
此外fmt包外还有一个打印方法:print,然而在golang中,其属于输出到标准错误流中并打印,官方不建议写程序时候用它,可以在debug时候用。

二、文件I/O

func main(){
    f, err := os.Create("user.txt")
    if err != nil {
        fmt.Println("Create err:", err)
    }
    defer f.Close()

    fmt.Println("create successful")
}
#输出
create successful

查看Create方法我们可以对返回值根据清晰,其中f为指针类型。

func Create(name string) (*File, error) {
    return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)

参1:name,表示打开文件的路径。可使用相对路径 或 绝对路径
参2:flag,表示读写模式,常见的模式有:
O_RDONLY(只读模式), O_WRONLY(只写模式), O_RDWR(可读可写模式), O_APPEND(追加模式)。|  O_CREATE (当有此参数,必须指定 参数3)  
参3:perm,表权限取值范围(0-7),表示如下:
0:没有任何权限
1:执行权限(如果是可执行文件,是可以运行的)
2:写权限
3: 写权限与执行权限
4:读权限
5: 读权限与执行权限
6: 读权限与写权限
7: 读权限,写权限,执行权限

借助OpenFile()方法,我们尝试进行文本的创建和写入:

func main() {
    filePath := "user.txt"
    file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
    checkErr(err)
    defer file.Close()

    str := "hello world\n"
    for i := 0; i < 3; i++ {
        file.WriteString(str)
    }
}

func checkErr(err error) {
    if err != nil {
        fmt.Println(err.Error())
        return
    }
}
#user.txt
hello world
hello world
hello world

此外,我们可以借助bufio包实现缓冲写入,即借助带缓存的*writer,所有操作先写入缓存,在执行Flush()方法是才写入文本。

func main() {
    filePath := "user.txt"
    file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
    checkErr(err)
    defer file.Close()

    str := "hello world\n"
    writer := bufio.NewWriter(file)
    for i := 0; i < 3; i++ {
        writer.WriteString(str)
    }
    writer.Flush()
}

func checkErr(err error) {
    if err != nil {
        fmt.Println(err.Error())
        return
    }
}
#user.txt
hello world
hello world
hello world

通过适度的缓冲区大小,我们可以提高Go在操作较大数据量时候的程序性能。

func main() {
    file, err := ioutil.ReadFile(`user.txt`)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(file))
}
#输出
hello world
hello world
hello world

使用缓冲区可依然借助os包和bufio实现:

func main() {
    file, err := os.Open("user.txt")
    checkErr(err)
    defer file.Close()
    reader := bufio.NewReader(file)
    for {
        str, err := reader.ReadString('\n')
        if err == io.EOF {
            break
        }
        fmt.Print(str)
    }
    fmt.Println("文件读取结束...")
}

func checkErr(err error) {
    if err != nil {
        fmt.Println(err.Error())
        return
    }
}
#输出
hello world
hello world
hello world
文件读取结束...
/狡辩

作为入门系列本章选取了较为主流且简单的实现方式,实际使用中可根据个人习惯选择。

上一篇下一篇

猜你喜欢

热点阅读