Go笔记6-Go IO

任何编程语言都有自己的IO系统,IO系统的接口设计是最能体现一门语言哲学的功底。而其中最具代表性的,就是文件、网络的I/O接口。

I/O

IO系统其实也可以从例子看起。首先我们看一个文件的例子。

// io.go
package main

import (
    "fmt"
    "os"
)

func main() {
    buf := make([]byte, 1024)
    f, e := os.Open("H:/ans.md") //打开文件, os.Open 返回一个实现了 io.Reader 和 io.Writer 的 *os.File;
    if e != nil {
        fmt.Println(e)
    }

    for {
        fmt.Println("BEGIN")
        n, _ := f.Read(buf) //一次读取 1024 字节;

        if n == 0 { //到达文件末尾
            fmt.Println("END")
            break
        }
        os.Stdout.Write(buf[0:n]) //将内容写入 os.Stdout
    }
    defer f.Close() //确保关闭了 f;
}


我们可以从这个例子中看出,对文件的IO是非常容易的。其实文件的读写两个方法分别实现了io.Reader和io.Writer,只要类的方法原型与这两个接口的原型相同,那么你可以任意为这些对象造型为io.Reader和io.Writer,让API更加“协议”化。

有时候,我们可能会遇到较大的文件,我们可以考虑使用缓冲IO包,可以通过缓冲的方式读写文件。

如下例:

package main

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

func main() {
    fmt.Print("Application started")
    var buf []byte = make([]byte, 1024)
    f, _ := os.Open("G:\\ans.md")
    defer f.Close()//保证即便发生恐慌最后也要执行关闭
    //这里返回的是一个Reader指针
    var r *bufio.Reader = bufio.NewReader(f)
    //这里返回的是一个Writer指针
    var w *bufio.Writer = bufio.NewWriter(os.Stdout)
    defer w.Flush()//保证即便发生恐慌最后也要执行关闭
    for {
        n, _ := r.Read(buf)
        if n == 0 {
            break
        }
        w.Write(buf[:n])
    }
}

如果要对一个目录操作,也是十分简单的

package main

import (
    "os"
    "fmt"
)

func main() {
    //我们希望判断一个目录存在与否
    if _, e := os.Stat("videos"); e != nil {
        os.Mkdir("videos", 0777)
        fmt.Println("文件夹不存在,已创建")

    } else {
        fmt.Println("文件夹已存在")
    }
}

命令行参数

我们可以从os.Args获取切片来获取输入的命令行参数,不过这限于无参数名参数,例如

mkdir filename

。flag包提供了带参数标识的参数,例如 -file /dev/null 这种,指定命令参数名一一对应的参数。 来举一个DNS解析的小例子(不是真的解析,还是看一下命令调用的方式和解析命令参数)

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    dnssec := flag.Bool("dnssec", false, "Request DNSSEC Record")
    port := flag.String("port", "53", "Set the query port")
    flag.Usage = func() {
        fmt.Fprint(os.Stdout, "Usage: %s [options] [name ...]\n", os.Args[0])
        flag.PrintDefaults()
    }
    flag.Parse()

    if *dnssec {
        fmt.Print(" dnssec :", *dnssec, "port: ", *port)
    }
}

执行系统命令 os/exec包有函数可以执行外部命令,可以很简单的调用命令行命令并做其他操作。

package main

import "os/exec"

func main() {
    var cmd *exec.Cmd = exec.Command("dir","/w")
    cmd.Run()
}

这是个很简单的命令调用,但是没有输出,如果我们的命令调用有输出的调用的话,那么我们就需要用cmd.Output()

...
    buf,err := cmd.Output() //buf是[]byte
...