Bruce Blog Bruce Blog
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航

Bruce Tao

运维界的该溜子
首页
  • CentOS
  • Ubuntu-Debian
  • 系统网络
  • 系统辅助工具
  • MySQL
  • Redis
  • Mongodb
  • Docker基础
  • Container基础
  • Kubernetes

    • Kubernetes基础
    • Kubernetes辅助
  • Container-Network
  • Jenkins
  • Gitlab
  • ArgoCD
  • Ansible
  • Terraform
  • AWS
  • MQ
  • NGINX
  • JumpServer
  • 基础
  • 函数模块
  • 框架
  • 基础

    • Golang环境
    • 语法
    • 数据类型与运算符
    • 分支语句
    • 循环语句
    • 数组
    • 切片
    • Map
    • String
    • 函数
    • 包的管理
    • 指针
    • 结构体
    • Go语言中的OOP
    • 方法和接口
    • 错误处理
  • Go进阶

    • Go进阶
  • Go框架

    • Go框架
  • Golang辅助

    • Golang辅助
  • CSS
  • HTML
  • JavaScript
  • 前端辅助
  • 常用命令
  • 性能监控工具
  • Windows下Docker使用
  • 日常学习
  • 其他导航
  • 基础

  • Go进阶

    • Go进阶
    • File操作
    • IO操作
    • 文件复制
    • 断点续传
    • bufio包
      • ioutil包
      • 遍历目录
      • 并发性Concurrency概念
      • Goroutine初识
      • Goroutine并发模型
      • Runtime包
      • 临界资源安全问题
      • sync包WaitGroup
      • 互斥锁
      • 读写锁
      • Channel通道
      • 关闭通道和通道上范围循环
      • 缓冲通道
      • 定向通道
      • time包中的通道相关函数
      • select语句
      • CSP并发模型
      • Go语言反射(一)
      • Go语言反射(二)
    • Go框架

    • Golang辅助

    • Golang
    • Go进阶
    Bruce
    2022-12-03
    目录

    bufio包

    # bufio包

    # 一、bufio包原理

    • https://golang.google.cn/pkg/bufio/

    • bufio是通过缓冲来提高效率

    • io操作本身的效率并不低,低的是频繁的访问本地磁盘的文件.所以bufio就提供了缓冲区(分配一块内存),读和写都现在缓冲区中,最后在读写文件,来降低访问本地此磁盘的次数,从而提高效率.

    • 简单的说就是,把文件读取进缓冲(内存)之后再读取的时候就可以避免文件系统的io从而提高速度.同理,在进行写操作时,先把文件写入缓冲(内存),然后由缓冲写入文件系统.前面描述可能会让人困惑,直接把内容---> 文件 和 内容 --->缓冲--->文件相比,缓冲区好像没有起到作用.其实缓冲区的设计使为了存储多次的写入,最后一口气把缓冲区内容写入文件.

    image-20221030215841270

    • bufio封装了io.Reader或io.Writer接口对象,并创建另一个也实现了该接口的对象.
    • io.Reader或io.Writer接口实现read()和write()方法,对于实现这个接口的对象都是可以使用这两个方法的.
    # Reader对象

    bufio.Reader是bufio中对io.Reader的封装

    // Reader implements buffering for an io.Reader object.
    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 //last byte read for UnreadByte; -1 means invalid
        lastRuneSize int //size fo last rune read for UnreadRune; -1 means invalid
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    bufio.Read(p []byte)相当于读取大小len(p)的内容,,思路如下:

    • 1.当缓存区有内容的时候,将缓存去内容全部填入p并清空缓存区
    • 2.当缓存区没有内容的时候且len(p)>len(buf),即要读取的内容比缓存区还要大,直接去文件读取即可
    • 3.当缓存区没有内容的时候且len(p) < len(buf),即要读取的内容比缓存区小,缓存区读取内容充满缓存区,并将p填满(此时缓存区有剩余内容)
    • 4.以后再次读取时缓存区有内容,将缓存区内容全部填入p并清空缓存区(此时和情况1一样)

    image-20221030221758745

    源码:

    // Read reads data into p.
    // It returns the number of bytes read into p.
    // The bytes are taken from at most one Read on the underlying Reader,
    // hence n may be less than len(p).
    // To read exactly len(p) bytes, use io.ReadFull(b, p).
    // At EOF, the count will be zero and err will be io.EOF.
    func (b *Reader) Read(p []byte) (n int, err error) {
        n = len(p)
        if n == 0 {
            return 0, b.readErr()
        }
        if b.r == b.w {
            if b.err != nil {
                return 0, b.readErr()
            }
            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()
            }
            // One read.
            // Do not use b.fill, which will loop.
            b.r = 0
            b.w = 0
            n, b.err = b.rd.Read(b.buf)
            if n < 0 {
                panic(errNegativeRead)
            }
            if n == 0 {
                return 0, b.readErr()
            }
            b.w += n
        }
    
        // copy as much as we can
        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
    }
    
    
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50

    说明:

    • reader内部通过维护一个r,w即读入和写入的位置索引来判断是否缓存区内容被全部读出.
    # bufio.NewReader
    # 实现方法
    // NewReader returns a new Reader whose buffer has the default size.
    func NewReader(rd io.Reader) *Reader {
    	return NewReaderSize(rd, defaultBufSize)
    }
    
    
    # 默认 bufsize
    const (
    	defaultBufSize = 4096
    )
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # Write对象
    • bufio.Write是bufio中对io.Writer的封装
    // Writer implements buffering for an io.Writer object.
    // If an error occurs writing to a Writer, no more data will be
    // accepted and all subsequent writes, and Flush, will return the error.
    // After all data has been written, the client should call the
    // Flush method to guarantee all data has been forwarded to
    // the underlying io.Writer.
    type Writer struct {
        err error
        buf []byte
        n   int
        wr  io.Writer
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    bufio.Write(p []byte)的思路如下:

    • 1.判断buf中可用容量是否可以放下p
    • 2.如果能放下,直接把p拼接到buf后面,即把内容放到缓冲区
    • 3.如果缓冲区的可用容量不足以放下,且此时缓冲区是空的,直接把p写入文件即可
    • 4.如果缓冲区的可用容量不足以放下,且此时缓冲区有内容,则用p把缓冲区填满,把缓冲区所有内容写入文件,并清空缓冲区
    • 5.判断p的剩余内容大小能否放到缓冲区,如果能放下(此时和步骤1情况一样)则把内容放到缓冲区
    • 6.如果p的剩余内容依旧大于缓冲区,(注意此时缓冲区是空的,情况和步骤3一样)则把p的剩余内容直接写入文件

    源码:

    // Write writes the contents of p into the buffer.
    // It returns the number of bytes written.
    // If nn < len(p), it also returns an error explaining
    // why the write is short.
    func (b *Writer) Write(p []byte) (nn int, err error) {
        for len(p) > b.Available() && b.err == nil {
            var n int
            if b.Buffered() == 0 {
                // Large write, empty buffer.
                // Write directly from p to avoid copy.
                n, b.err = b.wr.Write(p)
            } else {
                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
        }
        n := copy(b.buf[b.n:], p)
        b.n += n
        nn += n
        return nn, nil
    }
    
    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

    说明:

    • b.wr存储的是一个io.writer对象,实现了Write()的接口,所以可以使用b.wr.Write(p)将p的内容写入文件.
    • b.flush()会将缓存区内容写入文件,当所有写入完成后,因为缓存会存储内容,所需要手动flush()到文件.
    • b.Avaliable()为buf可用容量,等于len(buf) - n

    image-20221122135607568

    # bufio.NewWriter
    # 实现方法
    // NewWriter returns a new Writer whose buffer has the default size.
    // If the argument io.Writer is already a Writer with large enough buffer size,
    // it returns the underlying Writer.
    func NewWriter(w io.Writer) *Writer {
    	return NewWriterSize(w, defaultBufSize)
    }
    
    
    # 模式bufsize
    const (
    	defaultBufSize = 4096
    )
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 二、bufio包

    bufio包实现了有缓冲的I/O.它包装一个io.Reader或io.Writer接口对象,创建另一个也实现了该接口,且同时还提供了缓冲和一些文本I/O的帮助函数的对象.

    # bufio.Reader:

    bufio.Reader实现了如下接口: io.Reader io.WriterTo io.ByteScanner io.RuneScanner

    // NewReaderSize 将 rd 封装成一个带缓存的 bufio.Reader 对象,
    // 缓存大小由 size 指定(如果小于 16 则会被设置为 16).
    // 如果 rd 的基类型就是有足够缓存的 bufio.Reader 类型,则直接将
    // rd 转换为基类型返回.
    func NewReaderSize(rd io.Reader, size int) *Reader
    
    // NewReader 相当于 NewReaderSize(rd, 4096)
    func NewReader(rd io.Reader) *Reader
    
    // Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据,
    // 该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之
    // 前是有效的.如果切片长度小于 n,则返回一个错误信息说明原因.
    // 如果 n 大于缓存的总大小,则返回 ErrBufferFull.
    func (b *Reader) Peek(n int) ([]byte, error)
    
    // Read 从 b 中读出数据到 p 中,返回读出的字节数和遇到的错误.
    // 如果缓存不为空,则只能读出缓存中的数据,不会从底层 io.Reader
    // 中提取数据,如果缓存为空,则:
    // 1、len(p) >= 缓存大小,则跳过缓存,直接从底层 io.Reader 中读
    // 出到 p 中.
    // 2、len(p) < 缓存大小,则先将数据从底层 io.Reader 中读取到缓存
    // 中,再从缓存读取到 p 中.
    func (b *Reader) Read(p []byte) (n int, err error)
    
    // Buffered 返回缓存中未读取的数据的长度.
    func (b *Reader) Buffered() int
    
    // ReadBytes 功能同 ReadSlice,只不过返回的是缓存的拷贝.
    func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    
    // ReadString 功能同 ReadBytes,只不过返回的是字符串.
    func (b *Reader) ReadString(delim byte) (line string, err error)
    
    ...
    
    
    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
    # bufio.Writer:

    bufio.Writer实现了如下接口: io.Writer io.ReaderFrom io.ByteWriter

    // NewWriterSize 将 wr 封装成一个带缓存的 bufio.Writer 对象,
    // 缓存大小由 size 指定(如果小于 4096 则会被设置为 4096)。
    // 如果 wr 的基类型就是有足够缓存的 bufio.Writer 类型,则直接将
    // wr 转换为基类型返回。
    func NewWriterSize(wr io.Writer, size int) *Writer
    
    // NewWriter 相当于 NewWriterSize(wr, 4096)
    func NewWriter(wr io.Writer) *Writer
    
    // WriteString 功能同 Write,只不过写入的是字符串
    func (b *Writer) WriteString(s string) (int, error)
    
    // WriteRune 向 b 写入 r 的 UTF-8 编码,返回 r 的编码长度。
    func (b *Writer) WriteRune(r rune) (size int, err error)
    
    // Flush 将缓存中的数据提交到底层的 io.Writer 中
    func (b *Writer) Flush() error
    
    // Available 返回缓存中未使用的空间的长度
    func (b *Writer) Available() int
    
    // Buffered 返回缓存中未提交的数据的长度
    func (b *Writer) Buffered() int
    
    // Reset 将 b 的底层 Writer 重新指定为 w,同时丢弃缓存中的所有数据,复位
    // 所有标记和错误信息。相当于创建了一个新的 bufio.Writer。
    func (b *Writer) Reset(w io.Writer)
    
    ...
    
    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

    # 三、代码示例

    # 读取数据
    package main
    
    import (
        "os"
        "fmt"
        "bufio"
    )
    
    func main() {
        /*
        bufio:高效io读写
            buffer缓存
            io:input/output
    
        将io包下的Reader,Write对象进行包装,带缓存的包装,提高读写的效率
    
            ReadBytes()
            ReadString()
            ReadLine()
    
         */
    
         fileName:="/Users/ruby/Documents/pro/a/english.txt"
         file,err := os.Open(fileName)
         if err != nil{
            fmt.Println(err)
            return
         }
         defer file.Close()
    
         //创建Reader对象
         //b1 := bufio.NewReader(file)
         //1.Read(),高效读取
         //p := make([]byte,1024)
         //n1,err := b1.Read(p)
         //fmt.Println(n1)
         //fmt.Println(string(p[:n1]))
    
         //2.ReadLine()
         //data,flag,err := b1.ReadLine()
         //fmt.Println(flag)
         //fmt.Println(err)
         //fmt.Println(data)
         //fmt.Println(string(data))
    
         //3.ReadString()
        // s1,err :=b1.ReadString('\n')
        // fmt.Println(err)
        // fmt.Println(s1)
        //
        // s1,err = b1.ReadString('\n')
        // fmt.Println(err)
        // fmt.Println(s1)
        //
        //s1,err = b1.ReadString('\n')
        //fmt.Println(err)
        //fmt.Println(s1)
        //
        //for{
        //  s1,err := b1.ReadString('\n')
        //  if err == io.EOF{
        //      fmt.Println("读取完毕。。")
        //      break
        //  }
        //  fmt.Println(s1)
        //}
    
        //4.ReadBytes()
        //data,err :=b1.ReadBytes('\n')
        //fmt.Println(err)
        //fmt.Println(string(data))
    
        //Scanner
        //s2 := ""
        //fmt.Scanln(&s2)
        //fmt.Println(s2)
    
        b2 := bufio.NewReader(os.Stdin)
        s2, _ := b2.ReadString('\n')
        fmt.Println(s2)
    
    }
    
    
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    • 测试数据文件english.txt
    1.helloworld.
    
    2.鹅鹅鹅,曲项向天歌,拔毛加飘水,点火盖上锅。
    
    3.上联 no zuo no die why you cry,下联 you try you die don't ask why,横批,just do it
    
    4.女生说: 大海啊,母亲!男生说: 大海啊,丈母娘!
    
    5.大海啊都是水,骏马啊四条腿。
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 写数据
    package main
    
    import (
        "os"
        "fmt"
        "bufio"
    )
    
    func main() {
        /*
        bufio:高效io读写
            buffer缓存
            io:input/output
    
        将io包下的Reader,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)
    
         */
    
         fileName := "/Users/ruby/Documents/pro/a/cc.txt"
         file,err := os.OpenFile(fileName,os.O_CREATE|os.O_WRONLY,os.ModePerm)
         if err != nil{
            fmt.Println(err)
            return
         }
         defer file.Close()
    
         w1 := bufio.NewWriter(file)
         //n,err := w1.WriteString("helloworld")
         //fmt.Println(err)
         //fmt.Println(n)
    
         for i:=1;i<=1000;i++{
            w1.WriteString(fmt.Sprintf("%d:hello",i))
         }
         w1.Flush()
    }
    
    
    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
    39
    40
    41
    42
    上次更新: 2024/04/09, 16:48:42
    断点续传
    ioutil包

    ← 断点续传 ioutil包→

    最近更新
    01
    AWS NAT-NetWork-Firwalld配置(一)
    04-09
    02
    AWS NAT-NetWork-Firwalld配置(二)
    04-09
    03
    kubernetes部署minio对象存储
    01-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2024 Bruce Tao Blog Space | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式