欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

CloudGeek讲golang系列 - golang中的io操作

程序员文章站 2022-03-20 15:31:02
0、写在最前面 这篇文章讲什么?不讲什么? 我会从什么是io操作开始,逐步展开golang中的io知识体系;这个过程不会去按顺序介绍io包的所有接口啥的,那样做看似全面,其实很枯燥,看完就是忘完。如果你对IO操作有基础的认识,但是不知道golang中的io是怎么回事,那么下面的介绍会帮助你轻松入门了 ......

0、写在最前面

这篇文章讲什么?不讲什么?

我会从什么是io操作开始,逐步展开golang中的io知识体系;这个过程不会去按顺序介绍io包的所有接口啥的,那样做看似全面,其实很枯燥,看完就是忘完。如果你对IO操作有基础的认识,但是不知道golang中的io是怎么回事,那么下面的介绍会帮助你轻松入门了解io in go!

一、何为IO操作

 io操作简单理解就是从某处读/写到某处;比如读取键盘输入,读取文件,输出到终端,输出到一个文件……

二、golang中的io包

go语言的io 包提供了I/O原语的基本接口,我们先看最最基础的2个接口

  • io.Reader
  • io.Writer

CloudGeek讲golang系列 - golang中的io操作

CloudGeek讲golang系列 - golang中的io操作

如上所示,2个接口的定义很简单,都只包含一个方法,下面分别介绍

1、Read(p []byte) (n int, err error)

  • Read方法有一个[]byte类型的参数p,p相当于存放读取到的数据流的载体,p的长度可以大于实际接收到的数据,也就是容量为10的p可以只存放大小为5的数据,没有要求放满。
  • 当 Read 在成功读取 n > 0 个字节后遇到一个错误或EOF,它就会返回读取的字节数,此时err是nil或者EOF。

Read的用法应该还是容易理解,就是用一个p来暂存读取到的数据。任意一个类型只要实现了Read方法就算实现了Reader接口,也就成为了Reader接口的一个实例。如果暂时没有完全理解,等后面看完具体的用例再回过头来看看Read方法吧~

2、Write(p []byte) (n int, err error)

Write 将 len(p) 个字节的数据写入到基本数据流中。它返回从 p 中被写入的字节数 n(0 <= n <= len(p))以及任何遇到的引起写入提前停止的错误。若 Write 返回的 n < len(p),它就必须返回一个非nil的错误。也就是说p里应该全部是需要output的数据,全部完成写操作了就返回len(p)和nil,如果len(p)>n,也就是写中断了,这时候err必须有错误信息。

下面先看一下标准库中实现了io.Writer和io.Reader接口的那些类型是怎么工作的

三、golang中的文件io

1、os.File

 先看源码中怎么定义File的

CloudGeek讲golang系列 - golang中的io操作

注释是说File表示一个打开文件的描述符

File类型实现了十几个接口,其中包括了上面提到的io.Reader和io.Writer

先看一个简单的File读写文件操作(为了简化代码,突出重点,略去了错误处理等非功能代码)

  • 读取文件内容
func main() {
	//打开一个文件,文件里面存的是数字123
	f, _ := os.Open("d:\\1.txt")
	defer f.Close()
	//用一个长度为5的byte切片来读取数据
	b := make([]byte, 5)
	//n也就是读取到的数据长度
	n, _ := f.Read(b)
	//输出内容是:3 [49 50 51 0 0] 123  
	fmt.Println(n, b, string(b))
}
  • 数据写入文件
func main() {
	//创建文件
	f, _ := os.Create("d:\\666.txt")
	//待写入的数据
	b := []byte("CloudGeek")
	//执行写操作,n为写入的字符数
	n, _ := f.Write(b)
	//输出结果是:9
	fmt.Println(n)
}

上述代码很简短,实际文件读取操作的时候也不会这样用,不然就low了;这里只是为了给大家展示os.File类型实现了io.Writer和io.Reader接口,所以对应的Read和Write方法可以实现io操作,参数列表和返回值含义都是和前面介绍接口的时候讲的一样。

2、io/ioutil

  •  例子一:读取整个文件
func main() {
b, err := ioutil.ReadFile("d:\\1.txt")
if err == nil {
fmt.Println(string(b))
}
}
  • 例子二:写入数据到文件
func main() {
	//文件不存在会新建,权限通过perm指定,文件存在会被清空后再写入数据
	err := ioutil.WriteFile("d:\\3.txt", []byte("CloudGeek"), 0666)
	if err != nil {
		fmt.Println(err)
	}
}
  •  例子三:目录遍历
func main() {
	//目录遍历
	files, err := ioutil.ReadDir("d:\\d")
	if err != nil {
		fmt.Println(err)
	} else {
		for _, file := range files {
			fmt.Println("文件名:", file.Name(), "文件大小:", file.Size())
		}
	}
}
  • 例子四:读取任意实现了io.Reader接口的数据到一个[]byte中
func main() {
	//file是os.File类型,实现了io.Reader接口
	file, err := os.Open("d:\\d\\1.txt")
	if err != nil {
		fmt.Println(err)
	} else {
		//ReadAll方法接收io.Reader类型的参数,返回一个[]byte类型的结果
		b, err := ioutil.ReadAll(file)
		if err != nil {
			fmt.Println(err)
		} else {
			//[]byte类型的数据转换为string后输出
			fmt.Println(string(b))
		}
	}
}

3、bufio

bufio 包实现了带缓存的 I/O 操作,封装了io.Writer和io.Reader类型

  •  例子一:带缓存的写字符串
func main() {
	//创建文件(忽略错误处理过程)
	file, _ := os.Create("d:\\d\\1.txt")
	defer file.Close()

	//写入2个字符串到缓存区
	w := bufio.NewWriter(file)
	n1, _ := w.WriteString("CloudGeek!")
	n2, _ := w.WriteString("CloudGeek!")
	
	//将缓存中内容写到文件
	w.Flush()
	fmt.Println(n1, n2)
}

 这个例子中bufio.NewWriter返回的是bufio.Writer类型,这个类型封装了io.Writer,增加了buf等字段来支持缓存操作,定义如下:

CloudGeek讲golang系列 - golang中的io操作

四、golang中读取用户键盘输入

 先看一个及其简单的读取单个字符串输入的例子:

func main() {
	var username string
	fmt.Scanln(&username)
	fmt.Println("username is:", username)
}

在这个例子中,在控制台输入CloudGeek,得到的输出结果是:username is: CloudGeek

Scanln读取到换行或者EOF就会结束,中间读取到的字符串不能包含空格,不然就处理为多个字符串,这个例子中只用了一个username变量接收,所以如果输入:cloud geek,就只能获取到cloud。Scanln方法是从os.Stdin读取数据,Stdin是什么呢?如下:

CloudGeek讲golang系列 - golang中的io操作

NewFile的返回值是*File类型的变量,File类型实现了io.Writer和io.Reader接口,所以又和开始介绍的io包对应起来了。

 

本文主要带你了解golang中的IO,最主要是掌握io接口Writer和Reader,知道这个的基础上,在具体应用的时候无论是用到文件操作,缓存处理,终端输入输出等哪一块,再去查查相关用法的时候应该容易理解的多!