Go语言中,io
包提供了基本的输入输出接口和函数,它是Go语言中处理数据流的核心包之一。无论是文件、网络通信还是内存缓冲区的读写,我们都可能会使用到io
包。这篇笔记我们介绍io
包中的一些常用接口和函数。
io.Reader
接口用于读取数据。
type Reader interface {
Read(p []byte) (n int, err error)
}
p
:存储读取数据的缓冲区n
:实际读取的字节数err
:读取过程中发生的错误下面例子我们从一个文件中读取文本。
package main
import (
"fmt"
"os"
)
func main() {
// 打开源文件
file, err := os.Open("C:\\Users\\HUAWEI\\src.txt")
if err != nil {
fmt.Println(err)
return
}
// 关闭源文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
}
}(file)
// 从文件读取部分字节数据
buffer := make([]byte, 1024)
n, err := file.Read(buffer)
if err != nil {
fmt.Println(err)
}
// 打印读取的数据
fmt.Println(string(buffer[:n]))
}
os.Open()
函数返回的file
其实就实现了io.Reader
接口,我们可以从其中读取数据。代码中,我们创建了一个1024字节的切片,并调用Read()
方法从文件向其中读入数据,读取的数据字节数为n
。最后,我们将读取的数据转换为字符串并打印出来。
出于简单起见,上面代码最多仅会读取1024字节的数据,实际开发中,如果需要读取更多的数据,我们需要创建一个循环来调用Read()
方法。
注意:Go语言默认使用UTF-8
编码实现字节和字符串之间的转换。
io.Writer
接口用于写数据。
type Writer interface {
Write(p []byte) (n int, err error)
}
p
:要写入的数据n
:实际写入字节数err
:写入过程中发生的错误下面是一个例子。
package main
import (
"fmt"
"os"
)
func main() {
// 打开目标文件
file, err := os.OpenFile("C:\\Users\\HUAWEI\\target.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
fmt.Println(err)
return
}
// 关闭目标文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
return
}
}(file)
// 向文件写入数据
dataStr := "Hello, world!"
if _, err := file.Write([]byte(dataStr)); err != nil {
fmt.Println(err)
return
}
}
代码中,os.OpenFile()
函数返回的file
实现了io.Writer
接口,我们打开了文件并向其中写入一个字符串。
type Closer interface {
Close() error
}
上面代码中的file
其实也都实现了io.Closer
接口,用于关闭文件并释放相关的资源。
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
return
}
}(file)
io.Seeker
接口允许在数据流中移动读取和写入的位置。
type Seeker interface {
Seek(offset int64, whence int) (ret int64, err error)
}
offset
:偏移量(字节数)whence
:从哪里开始计算偏移量,0 文件开头,1 当前位置,2 文件结尾ret
:新的偏移位置err
:处理过程中发生的错误下面例子代码我们从文件开头偏移15字节读取数据。
package main
import (
"fmt"
"os"
)
func main() {
// 打开源文件
file, err := os.Open("C:\\Users\\HUAWEI\\src.txt")
if err != nil {
fmt.Println(err)
return
}
// 关闭源文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
}
}(file)
// 移动读取位置
if _, err := file.Seek(15, 0); err != nil {
fmt.Println(err)
}
// 从文件读取部分字节数据
buffer := make([]byte, 1024)
n, err := file.Read(buffer)
if err != nil {
fmt.Println(err)
}
// 打印读取的数据
fmt.Println(string(buffer[:n]))
}
io.Copy()
用于直接从Reader
中复制所有数据到Writer
,常用于文件复制,它的内部实际上有一个循环,该函数会阻塞直到Reader
返回EOF或发生错误。
func Copy(dst Writer, src Reader) (written int64, err error)
下面是一个例子代码,它实现了文件复制。
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开源文件
srcFile, err := os.Open("C:\\Users\\HUAWEI\\src.txt")
if err != nil {
fmt.Println(err)
return
}
// 关闭源文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
}
}(srcFile)
// 打开目标文件
targetFile, err := os.OpenFile("C:\\Users\\HUAWEI\\target.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
fmt.Println(err)
return
}
// 关闭目标文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
}
}(targetFile)
// 复制文件
written, err := io.Copy(targetFile, srcFile)
fmt.Printf("%v bytes copied\n", written)
}
io.CopyN()
和io.Copy()
类似,不过它最多会复制n
个字节的数据。
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
下面是一个例子。
// 复制文件
written, err := io.CopyN(targetFile, srcFile, 15)
fmt.Printf("%v bytes copied\n", written)
io.ReadAll()
用于读取Reader
中的所有数据,返回一个[]byte
切片。它的内部也是一个循环结构,会阻塞读取直到Reader
返回EOF或发生错误。
func ReadAll(r Reader) ([]byte, error)
下面例子使用io.ReadAll()
函数读取文件全部内容。
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开源文件
file, err := os.Open("C:\\Users\\HUAWEI\\src.txt")
if err != nil {
fmt.Println(err)
return
}
// 关闭源文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
return
}
}(file)
// 全部读取
data, err := io.ReadAll(file)
if err != nil {
fmt.Println(err)
return
}
// 打印读取的数据
fmt.Println(string(data))
}
io.ReadFull()
函数用于读取Reader
中的数据直到len(buffer)
个字节的数据,也就是我们需要阻塞等待读取直到填满缓冲区数组,如果读取期间Reader
返回EOF,则io.ReadFull()
函数返回io.ErrUnexpectedEOF
。
func ReadFull(r Reader, buf []byte) (n int, err error)
下面是一个例子,代码中我们读取文件的前15个字节。
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开源文件
file, err := os.Open("C:\\Users\\HUAWEI\\src.txt")
if err != nil {
fmt.Println(err)
return
}
// 关闭源文件逻辑
defer func(file *os.File) {
if err := file.Close(); err != nil {
fmt.Println(err)
return
}
}(file)
// 读取15个字节
buffer := make([]byte, 15)
if _, err := io.ReadFull(file, buffer); err != nil {
fmt.Println(err)
return
}
// 打印读取的数据
fmt.Println(string(buffer))
}