客户不应假定它们对于并行执行是安全的。
io库比较常用的接口有三个,分别是Reader,Writer和Closer。
1.1 Reader
type Reader interface {
Read(p []byte) (n int, err error)
}
io.Reader 表示一个读取器,它将数据从某个资源读取到传输缓冲区。在缓冲区中,数据可以被流式传输和使用。
- 对于要用作读取器的类型,它必须实现 io.Reader 接口的唯一一个方法 Read(p []byte)。
- 换句话说,只要实现了 Read(p []byte) ,那它就是一个读取器。
- Read() 方法有两个返回值,一个是读取到的字节数,一个是发生错误时的错误。
通过 string.NewReader(string) 创建一个字符串读取器,然后流式地按字节读取:
package day11
import (
"io"
"log"
"os"
"strings"
)
func D111() {
reader := strings.NewReader("dacheng test 123234")
// 每次读取4个字节
p := make([]byte, 4)
for {
n, err := reader.Read(p)
if err != nil {
// 剩下的内容不够4个字节
if err == io.EOF {
log.Printf("读完了:eof错误 : %d", n)
break
}
log.Printf("其他错误: %v", err)
os.Exit(2)
}
log.Printf("[读取到的字节数 %d][内容: %v]", n, string(p[:n]))
}
}
package main
import (
"go_pric/day11"
)
func main() {
day11.D111()
}
- 最后一次返回的 n 值有可能小于缓冲区大小。
- io.EOF 来表示输入流已经读取到头
1.1.1 文件操作相关API
-
func Create(name string) (file *File, err Error)
- 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666
-
func NewFile(fd uintptr, name string) *File
- 根据文件描述符创建相应的文件,返回一个文件对象
-
func Open(name string) (file *File, err Error)
- 只读方式打开一个名称为name的文件
-
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
- 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
-
func (file *File) Write(b []byte) (n int, err Error)
- 写入byte类型的信息到文件
-
func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
- 在指定位置开始写入byte类型的信息
-
func (file *File) WriteString(s string) (ret int, err Error)
- 写入string信息到文件
-
func (file *File) Read(b []byte) (n int, err Error)
- 读取数据到b中
-
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
- 从off开始读取数据到b中
-
func Remove(name string) Error
- 删除文件名为name的文件
1.1.2 读文件
os.Open()
函数能够打开一个文件,返回一个*File
和一个err
。对得到的文件实例调用Close()
方法能够关闭文件
type Closer interface {
Close() error
}
package day11
import (
"fmt"
"io"
"os"
)
func D112() {
// 打开文件
file, err := os.Open("day11/t.txt")
if err != nil {
fmt.Println("open file err :", err)
return
}
// 让出goroutine,先去执行下面的
defer file.Close()
// 定义接收文件读取的字节数组
var buf [128]byte
// 接收读取的文件
var content []byte
for {
n, err := file.Read(buf[:])
if err == io.EOF {
// 读取结束 跳出循环
break
}
if err != nil {
fmt.Println("read file err", err)
return
}
// buf[:n]... 这个是固定的Y欧诺个发
content = append(content, buf[:n]...)
}
// 将读取的内容转换成string输出
fmt.Println(string(content))
}
package main
import (
"go_pric/day11"
)
func main() {
day11.D112()
}
1.2 Writer
和Reader有异曲同工
type Writer interface {
//Write() 方法有两个返回值,一个是写入到目标资源的字节数,一个是发生错误时的错误。
Write(p []byte) (n int, err error)
}
- io.Writer 表示一个写入器,它从缓冲区读取数据,并将数据写入目标资源。
- 对于要用作编写器的类型,必须实现 io.Writer 接口的唯一一个方法 Write(p []byte)
- 同样,只要实现了 Write(p []byte) ,那它就是一个编写器。
1.3 bufio
- bufio包实现了带缓冲区的读写,是对文件读写的封装
- bufio缓冲写数据
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
package day11
import (
"bufio"
"fmt"
"io"
"os"
)
func Wr() {
// 参数2 : 打开模式,所有模式的含义在上述表格
// 参数3 是权限控制
// w 写 r读 x执行, w 2 r 4 x 1
// 0666 特殊权限位, 拥有者位, 同组用户位,其余用户位
file, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_RDONLY, 0666)
if err != nil {
fmt.Println(err)
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("./test.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
read := bufio.NewReader(file)
for {
line, _, err := read.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return
}
fmt.Println(string(line))
}
}
func D114() {
Wr()
Re()
}
1.4 ioutil工具包 (ioutil.WriteFile is deprecated: As of Go 1.16, this function simply calls [os.WriteFile].)
- ioutil库包含在io目录下,它的主要作用是
作为一个工具包
,里面有一些比较实用的函数 - 比如
ReadAll(从某个源读取数据)、ReadFile(读取文件内容)、WriteFile(将数据写入文件)、ReadDir(获取目录)
package day11
import (
"fmt"
"io/ioutil"
)
func We() {
err := ioutil.WriteFile("./t.txt", []byte("this is a lonely road\n"), 0666)
if err != nil {
fmt.Println(err)
return
}
}
func Re1() {
content, err := ioutil.ReadFile("./t.txt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(content))
}
func D115() {
We()
Re1()
}
1.5 实现一个cat命令
使用文件操作相关知识,模拟实现linux平台cat命令的功能。
package day11
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
// cat命令实现
func Cat(r *bufio.Reader) {
for {
line, _, err := r.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return
}
fmt.Println(string(line))
//注意是字符所以使用单引号
buf, err := r.ReadBytes('\n')
if err == io.EOF {
break
}
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
func D116() {
// 解析命令行参数
flag.Parse()
if flag.NArg() == 0 {
// 入股没有参数默认从标准输入读取内容
Cat(bufio.NewReader(os.Stdin))
}
// 依次读取每个指定文件的内容并打印到终端
for i := 0; i < flag.NArg(); i++ {
// 获取第i个文件名
f, err := os.Open(flag.Arg(i))
if err != nil {
fmt.Fprintf(os.Stdout, "reading form %s failed err:%v\n", flag.Arg(i), err)
continue
}
Cat(bufio.NewReader(f))
}
}