目录
go 语言的输入输出参考了 C 语言的输入输出,如果你学习过 C 语言,那么 go 的输入输出就很好理解了。
本文总结 go 中常用的输入输出方式,但是更详细的内容请同时参考官方文档,搭配起来一起看,因为官方文档的描述过于“非人话”。同时一些我觉得好的描述,也会直接挪用过来,更多的,我将用示例的方式直观展示。
先决条件
- 标准输入:从键盘上获取的输入
- 标准输出:输出到屏幕上
fmt 包
Scanln 与 Println
func Scanln(a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
Scanln 与 Scan 类似,但在换行符处停止扫描,并且在最后一项之后必须有一个换行符或 EOF。 空格用于分割数据。比如下面若要输入“张三”,要把“张”存入 firstName,“三”存入 lastName,中间用空格分开,即“张 三”,如果中间没有空格,则“张三”都会存入 firstName 中。
Println 按照默认格式进行输出。
fmt.Println("Please enter your full name by Scanln: ")
fmt.Scanln(&firstName, &lastName) // 键盘输入:张 三
fmt.Println("姓:"+firstName, "名:"+lastName) // 姓:张 名:三
Scanf 与 Printf
func Scanf(format string, a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
Scanf 格式化输入,即输入时完全按照定义的那样进行匹配,详见下方示例
Printf 格式化输出,用法同 Scanf 类型,只是它是输出
fmt.Println("Please enter your full name by Scanf: ")
fmt.Scanf("姓:%s,名:%s", &firstName, &lastName) // 键盘输入:姓:张,名:三
fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi 张,名:三 !
Sscanf
Sscanf 扫描参数字符串,将连续的空格分隔值存储到由格式确定的连续参数中。
此外,以 Sscan- 作为前缀(开头的)的函数,都是从一个字符串中寻找匹配的项。
fmt.Println("Please enter your full name by Sscanf: ")
fmt.Sscanf("zhangsan is 22 years old", "%s is %d years old", &name, &age)
fmt.Println(name, age) // zhangsan 22
Sprintf
func Sprintf(format string, a ...interface{}) string
Sprintf 将按照第一个参数中规定的格式输出
age := 10
s := fmt.Sprintf("我今年 %d 岁了", age)
io.WriteString(os.Stdout, s) // 控制台输出:我今年 10 岁了
更多 fmt 包的内容,不过都大同小异了
bufio 包
bufio 包提供了缓冲的读写功能,至于什么是缓冲,为什么使用缓冲以及缓冲的具体原理可以参考以下两篇文章,缓冲区机制详解 和 带缓冲 IO 与不带缓冲 IO 的区别与联系
fmt 包中的输入输出虽然借鉴了 C 语言,但是 C 的同名函数提供了缓冲器,但 go 中没有提供。
NewReader 与 ReadString
func NewReader(rd io.Reader) *Reader
func (b *Reader) ReadString(delim byte) (string, error)
NewReader 返回一个新的 Reader,其缓冲区具有默认大小。
ReadString 是一个 *Read 为接收器的方法,它会一直读取字符串,知道遇见手动指定的 delim,如 “\n”。详见下面的示例。
package main
import (
"fmt"
"bufio"
"os"
)
var inputReader *bufio.Reader
var input string
var err error
func main() {
inputReader = bufio.NewReader(os.Stdin)
fmt.Println("Please enter some input: ")
// 按下回车键后停止
input, err = inputReader.ReadString('\n')
if err == nil {
fmt.Printf("The input was: %s\n", input)
}
}
os 包
读取
os 为操作系统相关的包,提供操作系统相关功能。其中的 file 类型,则提供了文件读写的相关操作。
其中主要的核心是 os.Open
函数,Close
函数和文件结尾 io.EOF
上
func ReadFile() {
inputFile, inputError := os.Open("./readwritedata/readWrite.txt")
if inputError != nil {
fmt.Println(inputError)
return
}
// 不要忘记关闭文件,就像你家里的门一样,打开了就要关闭
defer inputFile.Close()
// 开启读取器
inputReader := bufio.NewReader(inputFile)
// 用一个死循环去读取内容
for {
// 按行读取,读取到 \n 就进入下一个循环
inputString, readerError := inputReader.ReadString('\n')
fmt.Printf("The input was: %s", inputString)
// 读到文件末位的时候,文件为 io.EOF 标识符,则退出
if readerError == io.EOF {
return
}
}
}
readWrite.txt
我们好像在哪见过
我们好像在哪儿见过你记得吗
好像那是一个春天我刚发芽
输出
The input was: 我们好像在哪见过
The input was: 我们好像在哪儿见过你记得吗
The input was: 好像那是一个春天我刚发芽
特别的,在类 Unix 和 Mac 下,结束符是 \n,而 Win 下结束符是 \r\n,但是使用 ReadString ,ReadBytes 和 ReadLine 无需考虑这个系统差异,直接 \n 即可。
写入
func WriteToFile() {
// OpenFile 提供三个参数
// 第一个参数是被打开的文件的名字
// 第二个参数是打开的方式,如 O_RDONLY:表示只读
// 第三个参数表示文件权限
outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
if outputError != nil {
fmt.Printf("An error occurred with file opening or creation\n")
return
}
defer outputFile.Close()
outputWriter := bufio.NewWriter(outputFile)
outputString := "hello world!\n"
for i := 0; i < 10; i++ {
outputWriter.WriteString(outputString)
}
// Flush 将缓冲数据写入底层的 io.Writer
outputWriter.Flush()
}
io 包
文件拷贝
使用 io.copy(dst,src)
方法进行文件的拷贝
io/ioutil 包
ioutil 包实现了一些 I/O 实用功能。
func ReadFileByIo() {
inputFile := "./readwritedata/readWrite.txt"
outputFile := "./readwritedata/readWrite2.txt"
// ReadFile 返回字节切片,其被存入 buf 中
buf, err := ioutil.ReadFile(inputFile)
if err != nil {
fmt.Println(err)
}
// 将字节切片转成字符串类型
fmt.Printf("%s\n", string(buf))
// 输出到其他文件中,若无文件,则创建该文件
err = ioutil.WriteFile(outputFile, buf, 0644) // oct, not hex
if err != nil {
panic(err.Error())
}
}
compress 包
compress 是关于压缩文件的包,目前支持:bzip2、flate、gzip、lzw 和 zlib 这些类型的压缩文件。
下面这段代码来自《go 入门指南》
package main
import (
"fmt"
"bufio"
"os"
"compress/gzip"
)
func main() {
fName := "MyFile.gz"
var r *bufio.Reader
fi, err := os.Open(fName)
if err != nil {
fmt.Fprintf(os.Stderr, "%v, Can't open %s: error: %s\n", os.Args[0], fName,
err)
os.Exit(1)
}
// 用 gzip 包中的 NewReader 来解压 gzip 文件
fz, err := gzip.NewReader(fi)
if err != nil {
r = bufio.NewReader(fi)
} else {
r = bufio.NewReader(fz)
}
for {
line, err := r.ReadString('\n')
if err != nil {
fmt.Println("Done reading file")
os.Exit(0)
}
fmt.Println(line)
}
}
参考
【1】标准输入输出
【2】go package 输入输出相关包
【3】《Go 入门指南》
【4】缓冲区机制详解
【5】带缓冲 IO 与不带缓冲 IO 的区别与联系