首页 > 其他分享 >go 库I/O

go 库I/O

时间:2024-01-24 12:11:06浏览次数:29  
标签:err int Writer 缓冲区 func Reader go

之前也有博客记录之 goio包

bufio

Reader

bufio.Readerio.Reader进行了包装,提供了缓冲区功能。定义如下:

type Reader struct {
    buf          []byte
    rd           io.Reader // reader provided by the client
    r, w         int       // buf read and write positions
    err          error
    lastByte     int       // 最后一个读取的字节,用于UnreadByte操作
    lastRuneSize int       // 最后一个读取rune的大小,用于UnreadRune操作
}

创建

通过NewReader(rd io.Reader)可以创建一个新的Reader:

func NewReader(rd io.Reader) *Reader {
    // const defaultBufSize = 4096
    // 默认缓冲区大小为4K
    return NewReaderSize(rd, defaultBufSize)
}

可以看到,NewReader实际上是调用了NewReaderSize方法,NewReaderSize会创建一个具有特定大小缓冲区的Reader:

func NewReaderSize(rd io.Reader, size int) *Reader {
    // Is it already a Reader?
    b, ok := rd.(*Reader)
    if ok && len(b.buf) >= size {
        return b
    }
    // const minReadBufferSize = 16
    // 缓冲区最小为16byte
    if size < minReadBufferSize {
        size = minReadBufferSize
    }
    r := new(Reader)
    r.reset(make([]byte, size), rd)
    return r
}

func (b *Reader) reset(buf []byte, r io.Reader) {
    *b = Reader{
        buf:          buf,
        rd:           r,
        lastByte:     -1,
        lastRuneSize: -1,
    }
}

read

和读操作相关的方法有:

  • func (b *Reader) Read(p []byte) (n int, err error)
  • func (b *Reader) ReadByte() (byte, error)
  • func (b *Reader) ReadRune() (r rune, size int, err error)
  • func (b *Reader) UnreadByte() error
  • func (b *Reader) UnreadRune() error
  • func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
  • func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
  • func (b *Reader) ReadBytes(delim byte) ([]byte, error)
  • func (b *Reader) ReadString(delim byte) (string, error)

其中Read方法源码为:

func (b *Reader) Read(p []byte) (n int, err error) {
    n = len(p)
    if n == 0 {
        return 0, b.readErr()
    }
    // 如果b.r == b.w,则当前缓冲区中无数据
    if b.r == b.w {
        if b.err != nil {
            return 0, b.readErr()
        }
        // 如果p的大小大于等于缓冲区大小,则直接将数据读入p,然后返回
        if len(p) >= len(b.buf) {
            // Large read, empty buffer.
            // Read directly into p to avoid copy.
            n, b.err = b.rd.Read(p)
            if n < 0 {
                panic(errNegativeRead)
            }
            if n > 0 {
                b.lastByte = int(p[n-1])
                b.lastRuneSize = -1
            }
            return n, b.readErr()
        }
        // 如果p的大小小于缓冲区大小,则先将数据读入缓冲区
        b.fill() // buffer is empty
        if b.r == b.w {
            return 0, b.readErr()
        }
    }

    // 将缓冲区中的数据尽可能的拷贝到p中
    n = copy(p, b.buf[b.r:b.w])
    b.r += n
    b.lastByte = int(b.buf[b.r-1])
    b.lastRuneSize = -1
    return n, nil
}

ReadSlice(delim byte)会读取数据直到遇到分隔符delim。如果在遇到delim之前出错了或者缓冲区满了,也会退出。

ReadLine()会读取一行数据,同样,在遇到换行符之前,如果出错了或者缓冲区满了,也会退出。因此该方法并不能保证遇到换行符的时候返回,也就是说,读到的数据可能并不够一行。例如:

r := strings.NewReader("0123456789abcdefghijklmn\nopqrstuvwxyz")
br := bufio.NewReaderSize(r, 16)
line, isPrefix, err := br.ReadLine()
fmt.Println(string(line)) // 0123456789abcdef
fmt.Println(isPrefix)     // true
fmt.Println(err)          // <nil>  

因此,如果想要按行读取数据,使用ReadBytes('\n')或者ReadString('\n')会是更好的选择。ReadString实际上调用了ReadBytes,只不过将数据转成了字符串而已。ReadBytes(delim byte)会不断地读取数据,直到遇到分隔符delim。例如:

r := strings.NewReader("0123456789abcdefghijklmn\nopqrstuvwxyz")
br := bufio.NewReaderSize(r, 16)
line, err := br.ReadBytes('\n')
fmt.Println(string(line)) // 0123456789abcdefghijklmn
fmt.Println(err)          // <nil>

其它操作

  • func (b *Reader) Buffered() int
  • func (b *Reader) Reset(r io.Reader)
  • func (b *Reader) Discard(n int) (discarded int, err error)
  • func (b *Reader) Peek(n int) ([]byte, error)
  • func (b *Reader) WriteTo(w io.Writer) (n int64, err error)

Buffered返回当前缓冲区中的可用数据量:

func (b *Reader) Buffered() int { return b.w - b.r }

Reset会重置数据源,之后的数据读取都会从新的数据源中来读:

func (b *Reader) Reset(r io.Reader) {
    b.reset(b.buf, r)
}

Discard(n int)会跳过之后的n个字节,例如:

br := bufio.NewReader(strings.NewReader("0123456789"))
p := make([]byte, 5)
br.Discard(3)
br.Read(p)
fmt.Println(string(p)) // 34567

Peek(n int)用于查看接下来的n个字节数据,但是并不真正读取,例如:

br := bufio.NewReader(strings.NewReader("0123456789"))
p := make([]byte, 5)
br.Peek(3)
br.Read(p)
fmt.Println(string(p)) // 01234

WriteTo将数据写入到一个Writer中,因此bufio.Reader实现了io.WriterTo接口。

Writer

bufio.Writerio.Writer进行了包装,提供了缓冲区功能。定义如下:

type Writer struct {
    err error
    buf []byte // 缓冲区
    n   int    // 缓冲区的可用数据量
    wr  io.Writer
}

通过如下方法可以创建新的Writer:

  • func NewWriter(w io.Writer) *Writer
  • func NewWriterSize(w io.Writer, size int) *Writer

write

写操作相关方法有:

  • func (b *Writer) Write(p []byte) (nn int, err error)
  • func (b *Writer) WriteByte(c byte) error
  • func (b *Writer) WriteRune(r rune) (size int, err error)
  • func (b *Writer) WriteString(s string) (int, error)

其中,Write方法源码为:

func (b *Writer) Write(p []byte) (nn int, err error) {
    // b.Available() 的值为 len(b.buf) - b.n
    // 只要p的大小大于缓冲区的可用大小,则执行循环
    for len(p) > b.Available() && b.err == nil {
        var n int
        if b.Buffered() == 0 {
            // 如果p的大小大于缓冲区的可用大小,且缓冲区为空
            // 则数据直接写入,无需先拷贝到缓冲区
            n, b.err = b.wr.Write(p)
        } else {
            // 将数据拷贝到缓冲区,然后通过flush操作写入缓冲区数据
            n = copy(b.buf[b.n:], p)
            b.n += n
            b.flush()
        }
        nn += n
        // 剩余待写入数据
        p = p[n:]
    }
    if b.err != nil {
        return nn, b.err
    }
    // 此时p的大小小于等于缓冲区大小,因此将数据拷贝到缓冲区
    n := copy(b.buf[b.n:], p)
    b.n += n
    nn += n
    return nn, nil
}

其它操作

  • func (b *Writer) Available() int
  • func (b *Writer) Buffered() int
  • func (b *Writer) Flush() error
  • func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
  • func (b *Writer) Reset(w io.Writer)

Available()返回的是缓冲区中的可用大小:

func (b *Writer) Available() int { return len(b.buf) - b.n }

Buffered()返回的是缓冲区中已经缓存的数据大小:

func (b *Writer) Buffered() int { return b.n }

ReadWriter

bufio.ReadWriter实现了io.ReadWriter接口,同时包含了一个Reader和一个Writer:

type ReadWriter struct {
    *Reader
    *Writer
}

func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
    return &ReadWriter{r, w}
}

标签:err,int,Writer,缓冲区,func,Reader,go
From: https://www.cnblogs.com/codestack/p/17984385

相关文章

  • 1.27号(本周六)直播:golang开发远程控制工具
    本次的课程的内容为:1、远控编写2、工具代码编写3、工具测试 1月27日晚20:00,我们不见不散~ Ms08067安全实验室专注于网络安全知识的普及和培训,是专业的“图书出版+培训”的网络安全在线教育平台,专注于网络安全领域中高端人才培养。平台已开设Web安全零基础就业,Web高级安全......
  • 2024-01-24:用go语言,已知一个n*n的01矩阵, 只能通过通过行交换、或者列交换的方式调整矩
    2024-01-24:用go语言,已知一个n*n的01矩阵,只能通过通过行交换、或者列交换的方式调整矩阵,判断这个矩阵的对角线是否能全为1,如果能返回true,不能返回false。我们升级一下:已知一个n*n的01矩阵,只能通过通过行交换、或者列交换的方式调整矩阵,判断这个矩阵的对角线是否能全为1,如果......
  • Golang map实现分析
    数据结构go的map采用数组+链表形式存储,数据存放于hmap中:typehmapstruct{countint//哈希表的元素个数,即len()flagsuint8//map状态Buint8//2^B为桶的数量noverflowuint16//溢出桶的数量(预估)hash0uint32//hashs......
  • Go Modules
    GoModules于1.11发布,自1.14之后推荐在生产中使用,其替代了传统的GOPATH模式,作为go的依赖管理工具。认识GOPATHGOPATH目录下一共包含了三个子目录,分别是:bin:存储所编译生成的二进制文件pkg:存储预编译的目标文件,以加快程序的后续编译速度src:存储所有.go文件或源代码。在编写Go......
  • 单实例mongodb 部署
    配置文件mkdir/data/mongopush/{log,data,conf,scripts,tmp}systemLog:destination:filelogAppend:truelogRotate:reopenpath:/data/mongopush/log/mongodb.logstorage:dbPath:/data/mongopush/datajournal:enabled:truedirectoryPerDB:tru......
  • Go-命令行参数解析
    1.解析命令行参数程序在执行时,获取在命令行启动程序是使用的参数命令行(Commandlineinterface--CLI):基于文本来查看、处理、操作计算机的界面,又被称为终端、控制台命令:在命令行执行的程序,一般是一行,包含命令名字、子命令与命令相关的选项(Flag),Flag:传递给命令的参数......
  • 从 fatal 错误到 sync.Map:Go中 Map 的并发策略
    从fatal错误到sync.Map:Go中Map的并发策略原创 波罗学 码途漫漫 2024-01-2121:00 发表于上海 听全文为什么Go语言在多个goroutine同时访问和修改同一个map时,会报出fatal错误而不是panic?我们该如何应对map的数据竞争问题呢?码途漫漫踏实地写......
  • arcengine GP调用PolygonToLine 报错 -2147467259
    这个原因是传参数问题;GP调用面转线工具时,不能利用该方式传入参数IGpValueTableObjectgpValueTableObject=newGpValueTableObject();//对一个及以上要素类进行相交运算gpValueTableObject.SetColumns(2);objecto1=pFeatureClass2;//输入IFeatureC......
  • GORM高级查询
    GORM高级查询准备数据typeStudentstruct{IDuint`gorm:"size:3"`Namestring`gorm:"size:8"`Ageint`gorm:"size:3"`GenderboolEmail*string`gorm:"size:32"`}func(stuStudent)TableName()s......
  • go-carbon v2.3.6 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
    carbon是一个轻量级、语义化、对开发者友好的golang时间处理库,支持链式调用。目前已被awesome-go收录,如果您觉得不错,请给个star吧github.com/golang-module/carbongitee.com/golang-module/carbon安装使用Golang版本大于等于1.16//使用github库goget-ugithu......