购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.2 通用I/O函数

在Go语言中,首先在io包中定义了一系列基本的I/O接口,然后面向这些接口还提供了众多便利的I/O函数。这些函数具有很强的实用性。接下来将详细探索这些通用函数的用法。

3.2.1 面向I/O接口的操作

Go语言的I/O操作可以很容易被抽象为流式数据处理,这就得益于标准库封装的各种的Copy和Read类函数。这些函数都是基于Reader、Writer来实现的。

❑ Copy、CopyN、CopyBuffer:这些函数负责将数据从Reader传输到Writer。它们底层使用相同的copyBuffer函数进行处理,该函数处理了I/O错误码、内部循环条件判断、EOF检测以及长度大小等问题。

❑ ReadFull、ReadAtLeast、ReadAll:这些函数专注于对Reader的操作,提供了完全读取、指定读取和读取全部等封装逻辑。

Reader接口定义了单次Read方法调用的行为,Writer接口定义了单次Write方法调用的行为,流式的I/O操作则是这些Read和Write调用组成的序列构成。其中最为经典的函数便是io.Copy,它对外提供了一个数据流的复制过程。该函数返回的是整个数据流复制的结果,而不仅仅是单次I/O操作的结果。

1.Copy系列函数

在Go语言的I/O库中,Copy系列函数扮演着数据复制的关键角色。以下是Copy系列函数的实现原理,如代码清单3-15所示。

代码清单3-15 Copy系列函数的实现原理

Copy系列函数都依赖于copyBuffer这一核心内部函数。copyBuffer的核心逻辑很简单:内部是一个大的for循环,每一次循环都执行一次Read,然后执行一次Write,直到所有数据被处理完毕或者遇到异常。因此,数据流的复制过程实际上就是由一系列的Read和Write构成的。

在copyBuffer的基础上,还衍生出了CopyN、CopyBuffer这两个复制函数。Copy函数处理的是无边界的数据流,而CopyN提供了数据量的限制功能,CopyBuffer则允许使用自定义的缓冲区来优化每次的I/O传输。

通过上述解析,我们可以了解到Copy系列函数是如何面向I/O接口编程的:这些函数专注于复制逻辑,从一个Reader里读取数据,然后将数据写到Writer里面,而不用关注Reader和Writer的具体类型。这种设计允许开发者将这些函数应用于多种Reader和Writer,提高了代码的复用性。

2.Read系列函数

Go语言处理数据流读取主要包括三个函数:ReadAll、ReadFull和ReadAtLeast。尽管它们都能读取数据流,但终止条件有所区别。

1)ReadAll函数持续读取数据直至遇到EOF或者发生错误。当ReadAll函数在正常情况下读到EOF时,并不会认为是异常,因此返回错误值仍为nil。该函数专注于数据流的整体读取状态。

2)ReadFull函数的目的是读取足够的数据以填满给定的缓冲区(即n==len(buf))。如果未能填满缓冲区(即n<len(buf)),则会返回错误。例如,如果在填满缓冲区之前遇到数据流的EOF,则会返回UnexpectedEOF错误。只要填满缓冲区,则返回值err是nil。该函数关注的是缓冲区的填充状态。

以下是ReadFull函数的实现,如代码清单3-16所示。

代码清单3-16 ReadFull函数的实现

3)ReadAtLeast函数用于确保至少读取了指定量的数据。它是ReadFull的底层实现。如果读取的数据量未达到指定的最小值(即n<min),则会返回报错。例如,在读取足够数据之前遇到数据流的EOF,则会返回UnexpectedEOF错误。一旦读取了指定的最小数据量,则返回值err是nil。这个函数关注的是读取数据量的大小。

ReadAtLeast函数的实现如代码清单3-17所示。

代码清单3-17 ReadAtLeast函数的实现

总的来说,若要简单读取整个数据流,ReadAll是合适的选择;若目标是填满一个缓冲区,那ReadFull会更适用;而ReadAtLeast则适合需要读取至少一定数量数据的场景。这些工具函数大大提高了存储编程的效率,简化了数据读取过程中的条件判断和错误处理。

3.2.2 文件I/O的操作函数

在存储编程实践中,文件I/O操作是常见且关键的一环。Go语言对此提供了丰富的工具函数,旨在帮助开发者快速实现文件的操作,减少了重复代码。值得注意的是,文件操作强依赖于操作系统,Go语言通过对os包中File类型的抽象操作来实现对系统文件的操作。这些文件操作的工具函数存放在os包中(曾位于io/ioutil包,自Go 1.16版本之后进行了重新整理)。

1)ReadFile:通过传入文件路径,可以直接把文件内容读到内存。这省去了开发者对Open、Read、Close的调用。

2)WriteFile:允许用户将数据从内存一次性写入文件中。这省去了开发者对Open、Write、Close的调用。

3)ReadDir:通过传入目录路径,可以快速获取该路径下所有文件的列表。

这些函数简化了开发者对文件的操作。接下来深入分析ReadFile函数的实现原理,如代码清单3-18所示。

代码清单3-18 ReadFile函数的实现原理

使用ReadFile函数可以轻松地将整个文件内容读到内存,数据被存放在一个字节切片中。然而,这种方式需要注意文件的大小,以防文件过大而超出内存容量。

在处理配置文件(即文件大小可控的场景)时,ReadFile和WriteFile显得尤为便捷,它们提供了一个简洁的方法来实施配置数据的读取和存储。这两个函数的使用可以简化配置管理过程,让文件的读写变得直接而高效。 /Gc9LvCjus54sVU3CLFL83F/U+9h1I7kGynyTY18ej+zj3xbAsrxM0LTqMr1OZ/b

点击中间区域
呼出菜单
上一章
目录
下一章
×

打开