在 Go 中,从文件读取(或写入)是非常容易的。程序只需要使用 os 包就可以从文件 /etc/passwd 中读取数据。
从文件读取(无缓冲)
1 | package main |
如果想要使用缓冲 IO,则有 bufio 包:
1 | package main |
io.Reader
在前面已经提到 io.Reader 接口对于 Go 语言来说非常重要。许多函数需要通过 io.Reader 读取一些数据作为输入。为了满足这个接口,只需要实现一个方法:Read(p []byte) (n int, err error)。写入则是(你可能已经猜到了)实现了 Write 方法的 io.Writer。如果你让自己的程序或者包中的类型实现了 io.Reader 或者 io.Writer 接口,那么整个 Go 标准库都可以使用这个类型。
行读取
1 | f, _ := os.Open("/etc/passwd") |
更加通用(但是也更加复杂)的方法是 ReadLine,可以参阅包 bufio 的文档了解更多内容。
在 shell 脚本中通常遇到的场景是需要检查某个目录是否存在,如果不存在,就创建一个。我们可以用go实现一下:
1 | if f, e := os.Stat("name") ; e !=nil { |
这个例子展示了 Go 拥有的 “脚本” 化特性,用 Go 编写程序感觉上类似使用动态语言(Python、Ruby、Perl 或者 PHP)。
命令行参数
来自命令行的参数在程序中通过字符串 slice os.Args 获取,导入包 os 即可。flag 包有着精巧的接口,同样提供了解析标识的方法。这个例子是一个 DNS 查询工具:
1 | dnssec := flag.Bool("dnssec", false, "Request DNSSEC records") // 定义 bool 标识,-dnssec。变量必须是指针,否则 package 无法设置其值 |
命令执行
os/exec 包有函数可以执行外部命令,这也是在 Go 中主要的执行命令的方法。通过定义一个有着数个方法的 *exec.Cmd 结构来使用。
执行ls -l的例子:
1 | // 不对返回的数据进行处理 |
网络
所有网络相关的类型和函数可以在 net 包中找到。其中最重要的函数是 Dial。当Dial 到远程系统,这个函数返回 Conn 接口类型,可以用于发送或接收信息。函数Dial 简单的抽象了网络层和传输层。因此 IPv4 或者 IPv6,TCP 或者 UDP 可以共用一个接口。
通过 TCP 连接到远程系统(端口 80),然后是 UDP,最后是 TCP 通过 IPv6,大致是这样:
1 | conn, e := Dial("tcp", "192.0.32.10:80") |
如果没有错误(由 e 返回),就可以使用 conn 从套接字中读写。在包 net 中的原始定义是:
1 | Read(b []byte)(n int, err error) // 使conn成为了io.Reader |
这都是些比较低层的东西,我们一般用的使更高层的包,比如http:
1 | package main |