日常的开发中关于终端的输入以及文件的操作还是比较多的,这篇文章主要把关于这两方面的操作进行整理

终端操作

格式化输入

获取终端的输入,这里需要注意的是当在终端输入的时候默认是以空格做分割的,就像我们下面三个值,我们每个输入之间需要通过空格进行隔开

package main

import "fmt"

func main() {
    var a int
    var b string
    var c float64

    fmt.Scanf("%d%s%f",&a,&b,&c)
    fmt.Printf("a= %d b=%s c=%f\n",a,b,c)
}

如下述效果:

23 name 12.2
a= 23 b=name c=12.200000

如果我们想以换行的方式一个一个输入,则需要对代码进行改造如下:

package main

import "fmt"

func main() {
    var a int
    var b string
    var c float64
    //fmt.Scanf("%d%s%f",&a,&b,&c)
    fmt.Scanf("%d\n",&a)
    fmt.Scanf("%s\n", &b)
    fmt.Scanf("%f\n",&c)
    fmt.Printf("a= %d b=%s c=%f\n",a,b,c)
}

效果如下:

23
zhaofan
2.2
a= 23 b=zhaofan c=2.200000

关于scan的使用,通过scan获取用户输入的时候就比较灵活了,不管是通过空格还是通过换行的方式都是可以的

package main

import "fmt"

func main() {
    var a int
    var b string
    var c float64
    fmt.Scan(&a,&b,&c)
    fmt.Printf("a=%d b=%s c=%f\n",a,b,c)
}

如果是通过scanln获取用户输入的话,则是以换行为结束的,所以如果我们还想要分别获取a b c的值则需要通过通过空格的方式进行隔开

与上面三个与之对应的还有三个从字符串中获取输入的方法: fmt.Sscanf fmt.Sscan fmt.Sscanln 不同的地方就是这次的输入源是从字符串

就以Sscanf写一个例子:

package main

import "fmt"

func main() {
    var a int
    var b string
    var c float64
    var str string = "22 zhaofan 2.2"
    fmt.Sscanf(str,"%d%s%f\n",&a,&b,&c)
    fmt.Printf("a=%d  b=%s  c=%f\n", a,b,c)
}

格式化输出

下面三个是格式化输出到终端的: fmt.Printf fmt.Println fmt.Print

下面三个是格式化输出到字符串的: fmt.Sprintf: 格式化并返回字符串 fmt.Sprintln: 把零个或多个变量按空格格式进行格式化并换行 fmt.Sprint : 把零个或多个变量按空格进行格式化,返回字符串

终端

终端相关的文件的实例:

os.Stdin: 标准输入的文件实例,类型为*File

os.Stdout: 标准输出的文件实例,类型为*File

os.Stderr: 标准错误输出的文件实例,类型为*File

从文件获取输入

fmt.Fscanf : 从文件格式化输入,空格作为分隔符

fmt.Fscanln: 从文件获取用户输入,空格和换行作为分隔符

fmt.Fscan: 从文件获取用户输入,空格作为分隔符,遇到换行符结束

buffio从终端读取一行数据

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    var str string
    reader := bufio.NewReader(os.Stdin)
    str, _ = reader.ReadString('\n')
    fmt.Println(str)
}

os.Args 命令行参数的切片

os.Args第0个元素就是当前程序的名字

package main

import (
    "fmt"
    "os"
    "strings"
)

func main() {
    name := "dean"
    if len(os.Args) > 1 {
        name += strings.Join(os.Args[1:],"")
    }
    fmt.Println(os.Args[0])
    fmt.Println("Hello:", name)
}

使用flag包获取命令行参数

使用例子如下:

package main

import (
    "flag"
    "fmt"
)

var (
    recusive bool
    test string
    level int
)

func init() {
    flag.BoolVar(&recusive,"r", false, "bool类型")
    flag.StringVar(&test, "t", "default ddd", "字符串类型")
    flag.IntVar(&level,"l", 1,"flag xxx")
    flag.Parse()
}

func main() {
    fmt.Printf("recusive=%v   test=%s   level=%v\n", recusive, test,level)
}

cli框架的简单使用

github.com/urfave/cli 这个框架是封装了比flag更好的使用,下面是一个简单的例子:

package main

import (
    "fmt"
    "github.com/urfave/cli"
    "os"
)

func main() {
    var language string
    var recusive bool
    app := cli.NewApp()
    app.Flags= []cli.Flag{
        cli.StringFlag{
            Name: "lang,l",
            Value: "english",
            Usage: "language for the greeting",
            Destination: &language,
        },
        cli.BoolFlag{
            Name: "recusive,r",
            Usage: "recusive for the greeting",
            Destination: &recusive,
        },
    }
    app.Action = func(c *cli.Context) error {
        var cmd string
        // c.Narg() 可以获取参数的个数
        if c.NArg() > 0 {
            cmd = c.Args()[0]
            fmt.Println("cmd is", cmd)
        }
        fmt.Println("recusive is ",recusive)
        fmt.Println("language is ", language)
        return nil
    }
    app.Run(os.Args)
}

文件操作

os.Open

通过os.Open的方式获取的*file对象对文件的操作是==只读的== 返回的*file对象常用的有两个方法:Read和ReadAt Read是从当前位置读取一定字节的内容 ReadAt是:ReadAt reads len(b) bytes from the File starting at byte offset off. 也就是从文件开始偏移一定数量的字节之后开始读取一定数量的字节内容

一个简单的代码例子如下:

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    // 这里是以只读的方式打开文件
    file, err := os.Open("./file")
    if err != nil {
        fmt.Println("open file error:",err)
        return
    }


    var buf[1024]byte
    var content []byte
    for {
        len, err := file.Read(buf[:])
        // 表示已经读到文件末尾
        if err == io.EOF {
            break
        }
        if err != nil {
            fmt.Println("read file error:",err)
            return
        }
        content = append(content, buf[:len]...)
    }
    fmt.Println(string(content))

    defer file.Close()
}

从上面的使用我们也可以知道这种方式读文件只能按照字节的方式读取,其实我们的日常文件操作可能更多的是一行一行的读取文件 那么就需要用到bufio的方式

os.OpenFile

os.O_WRONLY:只写 os.O_CREATE:创建文件 os.O_RDONLY:只读 os.O_RDWR: 读写 os.O_TRUNC: 清空 os.O_APPEND:追加

buffio操作文件

通过buffio一行一行的读文件内容

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    inputFile, err := os.Open("./file")
    if err != nil {
        fmt.Println("oepn file error:",err)
        return
    }
    defer inputFile.Close()
    inputReader := bufio.NewReader(inputFile)

    for {
        // 这里是按行读取文件
        inputString, readrError := inputReader.ReadString('\n')
        //读到文件末尾
        if readrError == io.EOF {
            return
        }
        fmt.Println("input file is :", inputString)
    }

}

buffio的写文件,下面的例子中,我们打开文件时设置了os.O_CREATE
os.O_APPEND,所有如果文件不存在则会创建文件,如果文件存在则会进行追加的方式写文件

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    f, err := os.OpenFile("test",os.O_RDWR|os.O_CREATE|os.O_APPEND,0755)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer f.Close()
    bufioW := bufio.NewWriter(f)
    n, _ := bufioW.WriteString("Hello Golang")
    fmt.Println(n)
    bufioW.Flush()
}

ioutil操作文件

读取整个文件,代码例子如下:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    // 读取整个文件
    content, err := ioutil.ReadFile("file")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(content))
}

而通过ioutil写文件的方式更加简单:

package main

import (
    "io/ioutil"
)

func main() {
    err:= ioutil.WriteFile("test",[]byte("My Name is GoLang"),0755)
    if err != nil {
        return
    }
}