IO

1. 什么是IO

I/O操作也叫输入输出操作。其中I是指InputO是指Output,用于或者数据的。

image-20240327231531265

数据是通过IO总线进行流动,数据在磁盘和内存之间流动,称之为磁盘IO,数据在网络和内存之间流动,称之为网络IO

  • io包提供io操作的基本接口
  • fmt包实现了格式化io操作
  • bufio实现了带缓冲的io操作

2. io包

io包主要提供了以下几个接口:

  • io.Reader:代表一个可读取数据的接口。它定义了一个 Read 方法,用于从数据源读取数据到字节切片。
  • io.Writer:代表一个可写入数据的接口。它定义了一个 Write 方法,用于将数据写入目标。
  • io.Closer:代表一个可以关闭的接口,通常用于关闭文件或网络连接。它定义了一个 Close 方法。
  • io.Seeker:代表一个可以寻址的接口,通常用于定位和设置数据源的位置。它定义了一个 Seek 方法。

2.1 Reader

type Reader interface {
	Read(p []byte) (n int, err error)
}
1
2
3
  • io.Reader 表示一个读取器,它将数据从某个资源读取到传输缓冲区。
  • 入参:字节切片p,会将数据读入到 p 中
  • 返回值:本次读取的字节数 n,以及遇到的错误 err
  • 只要实现了 Read方法 ,那它就是一个读取器

比如通过 string.NewReader(string) 创建一个字符串读取器

func main() {
	reader := strings.NewReader("B站码神之路go教程")
	num := 0
	all := make([]byte, 0)
	for {
		p := make([]byte, 4)
		n, err := reader.Read(p)
		if err != nil {
			if err == io.EOF {
				fmt.Println("读取完成")
				log.Printf("读取的的字节数:%d和内容:%v \n", num, string(all[:num]))
				break
			}
			log.Fatalf("读取错误:%v \n", err)
		}
		num += n
		all = append(all, p...)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

读取文件示例:

func readFile(path string) {
	file, err := os.Open(path)
	if err != nil {
		log.Fatal(err)
	}
    //注意关闭文件流
    defer file.Close()
	buff := make([]byte, 1024)
	for {
		n, err := file.Read(buff)
		if err != nil {
			if err == io.EOF {
				fmt.Println("读完了")
				break
			}
			log.Fatal(err)
		}
		fmt.Printf("读取到的内容:%v \n ", string(buff[:n]))
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

2.2 Writer

type Writer interface {
    //Write() 方法有两个返回值,一个是写入到目标资源的字节数,一个是发生错误时的错误。
    Write(p []byte) (n int, err error)
}
1
2
3
4
  • io.Writer 表示一个写入器,它从缓冲区读取数据,并将数据写入目标资源。
  • 只要实现了 Write(p []byte) ,那它就是一个写入器。
func writeFile(content string) {
	// 新建文件
	file, err := os.Create("./test.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	_, err = file.Write([]byte(content))
	if err != nil {
		return
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14

2.3 Seeker

type Seeker interface {
    //用于指定下次读取或者写入时的偏移量
	Seek(offset int64, whence int) (int64, error)
}
const (
	SeekStart   = 0 // 基于文件开始位置
	SeekCurrent = 1 // 基于当前偏移量 
	SeekEnd     = 2 // 基于文件结束位置
)
1
2
3
4
5
6
7
8
9
  • 入参:计算新偏移量的起始值 whence, 基于whence的偏移量offset
  • 返回值:基于 whence 和 offset 计算后新的偏移量值,以及可能产生的错误
模式含义
os.O_WRONLY只写
os.O_CREATE创建文件
os.O_RDONLY只读
os.O_RDWR读写
os.O_TRUNC清空
os.O_APPEND追加
func writeFile(content string) {
    // 打开文件 
    // 参数2:打开模式
    // 参数3是权限控制
    // w写 r读 x执行   w  2   r  4   x  1
    //特殊权限位,拥有者位,同组用户位,其余用户位
    file, err := os.OpenFile("./test.txt", os.O_RDWR, 655)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	_, err = file.Seek(4, io.SeekStart)
	if err != nil {
		log.Fatal(err)
	}
	_, err = file.Write([]byte(content))
	if err != nil {
		log.Fatal(err)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

2.4 文件操作API

 func Create(name string) (file *File, err Error)
1
  • 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666
 func NewFile(fd uintptr, name string) *File
1
  • 根据文件描述符创建相应的文件,返回一个文件对象
 func Open(name string) (file *File, err Error)
1
  • 只读方式打开一个名称为name的文件
 func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
1
  • 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
 func (file *File) Write(b []byte) (n int, err Error)
1
  • 写入byte类型的信息到文件
 func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
1
  • 在指定位置开始写入byte类型的信息
 func (file *File) WriteString(s string) (ret int, err Error)
1
  • 写入string信息到文件
 func (file *File) Read(b []byte) (n int, err Error)
1
  • 读取数据到b中
 func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
1
  • 从off开始读取数据到b中
 func Remove(name string) Error
1
  • 删除文件名为name的文件

3. bufio

  • bufio.Reader:代表一个带缓冲的读取器,允许从输入流中按行或字节块读取数据。
  • bufio.Writer:代表一个带缓冲的写入器,允许将数据写入输出流并控制何时执行实际的写入操作。
func wr() {
    // 参数2:打开模式,所有模式d都在上面
    // 参数3是权限控制
    // w写 r读 x执行   w  2   r  4   x  1
    //特殊权限位,拥有者位,同组用户位,其余用户位
    file, err := os.OpenFile("./xxx.txt", os.O_CREATE|os.O_WRONLY, 0666)
    if err != nil {
        return
    }
    defer file.Close()
    // 获取writer对象
    writer := bufio.NewWriter(file)
    for i := 0; i < 10; i++ {
        writer.WriteString("hello\n")
    }
    // 刷新缓冲区,强制写出
    writer.Flush()
}

func re() {
    file, err := os.Open("./xxx.txt")
    if err != nil {
        return
    }
    defer file.Close()
    reader := bufio.NewReader(file)
    for {
        line, _, err := reader.ReadLine()
        if err == io.EOF {
            break
        }
        if err != nil {
            return
        }
        fmt.Println(string(line))
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

4. ioutil工具

  • ioutil库包含在io目录下,它的主要作用是作为一个工具包,里面有一些比较实用的函数
  • 比如 ReadAll(从某个源读取数据)ReadFile(读取文件内容)WriteFile(将数据写入文件)ReadDir(获取目录)
func wr() {
   err := ioutil.WriteFile("./yyy.txt", []byte("码神之路"), 0666)
   if err != nil {
      fmt.Println(err)
      return
   }
}

func re() {
   content, err := ioutil.ReadFile("./yyy.txt")
   if err != nil {
      fmt.Println(err)
      return
   }
   fmt.Println(string(content))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16