go 的读写大总结


go 语言的输入输出参考了 C 语言的输入输出,如果你学习过 C 语言,那么 go 的输入输出就很好理解了。

本文总结 go 中常用的输入输出方式,但是更详细的内容请同时参考官方文档,搭配起来一起看,因为官方文档的描述过于“非人话”。同时一些我觉得好的描述,也会直接挪用过来,更多的,我将用示例的方式直观展示。

先决条件

  1. 标准输入:从键盘上获取的输入
  2. 标准输出:输出到屏幕上

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 即可。

写入

  1. 关于打开方式点击这里查看官方文档
  2. 关于文件权限点击这里了解详细内容
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 的区别与联系

Guess you like

Origin blog.csdn.net/qq_34902437/article/details/121116609
Go