golang bufio包

package main

import (
    "bufio"
    "fmt"
    "strings"
    "bytes"
    "io"
)

// bufio 包实现了带缓存的 I/O 操作

/**
 * 首先看reader和writer基本的结构
 * // 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
 *  lastRuneSize int
 * }
 *
 *
 * // 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 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
 * }
 *
 *
 *
 * // ReadWriter 集成了 bufio.Reader 和 bufio.Writer, 实现了 io.ReadWriter 接口
 * type ReadWriter struct {
 *  *Reader
 *  *Writer
 * }
 */

func main()  {
    // 1: 使用bufio.NewReader构造一个reader
    inputReadBuf := strings.NewReader("1234567890")
    reader := bufio.NewReader(inputReadBuf)


    // 2: 使用bufio.NewWriter构造一个writer
    buf := bytes.NewBuffer(make([]byte, 0))
    writer := bufio.NewWriter(buf)


    // 3: 函数Peek函数: 返回缓存的一个Slice(引用,不是拷贝),引用缓存中前n字节数据
    // > 如果引用的数据长度小于 n,则返回一个错误信息
    // > 如果 n 大于缓存的总大小,则返回 ErrBufferFull
    // 通过Peek的返回值,可以修改缓存中的数据, 但不能修改底层io.Reader中的数据
    b, err := reader.Peek(5)
    if err != nil {
        fmt.Printf("Read data error")
        return
    }
    // 修改第一个字符
    b[0] = 'A'
    // 重新读取
    b, _ = reader.Peek(5)
    writer.Write(b)
    writer.Flush()
    fmt.Println("buf(Changed): ", buf, "\ninputReadBuf(Not Changed): ", inputReadBuf)


    // 4: Read函数, 每次读取一定量的数据, 这个由buf大小觉得, 所以我们可以循环读取数据, 直到Read返回0说明读取数据结束
    for {
        b1 := make([]byte, 3)
        n1, _ := reader.Read(b1)
        if n1 <= 0 {
            break
        }
        fmt.Println(n1, string(b1))
    }


    // 5: ReadByte和UnreadByte函数
    // ReadByte 从 b 中读出一个字节并返回, 如果 b 中无可读数据,则返回一个错误
    // UnreadByte 撤消最后一次读出的字节, 只有最后读出的字节可以被撤消, 无论任何操作,只要有内容被读出,就可以用 UnreadByte 撤消一个字节
    inputReadBuf2 := strings.NewReader("1234567890")
    reader2 := bufio.NewReader(inputReadBuf2)
    // 读一个字节
    b2, _ := reader2.ReadByte()
    fmt.Println(string(b2))
    // Unread一个字节
    reader2.UnreadByte()
    b2, _ = reader2.ReadByte()
    fmt.Println(string(b2))


    // 6: ReadRune和UnreadRune函数, 类似上面两个函数
    // ReadRune读出一个 UTF8 编码的字符并返回编码长度, 如果UTF8序列无法解码出一个正确的Unicode字符, 则只读出b中的一个字节,size 返回 1
    inputReadBuf3 := strings.NewReader("中文1234567890")
    reader3 := bufio.NewReader(inputReadBuf3)
    b3, size, _ := reader3.ReadRune()
    fmt.Println(string(b3), size)
    reader3.UnreadRune()
    b3, size, _ = reader3.ReadRune()
    fmt.Println(string(b3), size)
    // 执行UnreadRune时候, 如果之前一步不是ReadRune, 那么会报错, 看下面
    b33, _ := reader3.ReadByte()
    fmt.Println(string(b33))
    err3 := reader3.UnreadRune()
    if err3 != nil {
        fmt.Println("ERR")
    }


    // 7: 读取缓冲区中数据字节数(只有执行读才会使用到缓冲区, 否则是没有的)
    inputReadBuf4 := strings.NewReader("中文1234567890")
    reader4 := bufio.NewReader(inputReadBuf4)
    // 下面返回0, 因为还没有开始读取, 缓冲区没有数据
    fmt.Println(reader4.Buffered())
    // 下面返回strings的整体长度16(一个人中文是3长度)
    reader4.Peek(1)
    fmt.Println(reader4.Buffered())
    // 下面返回15, 因为readByte已经读取一个字节数据, 所以缓冲区还有15字节
    reader4.ReadByte()
    fmt.Println(reader4.Buffered())
    // 下面的特别有意思: 上面已经读取了一个字节, 想当于是将"中"读取了1/3, 那么如果现在使用readRune读取, 那么
    // 由于无法解析, 那么仅仅读取一个byte, 所以下面的结果很显然
    // 第一次: 无法解析, 那么返回一个byte, 所以输出的是14
    reader4.ReadRune()
    fmt.Println(reader4.Buffered())
    // 第二次读取, 还剩下"中"最后一个字节, 所以也会err, 所以输出13
    reader4.ReadRune()
    fmt.Println(reader4.Buffered())
    // 现在"中"读完了, 那么开始完整读取"文", 这个OK的, 可以解析的, 所以可以读取三字节, 那么剩下10字节
    reader4.ReadRune()
    fmt.Println(reader4.Buffered())


    // 8: ReadSlice查找 delim 并返回 delim 及其之前的所有数据的切片, 该操作会读出数据,返回的切片是已读出数据的"引用"
    // 如果 ReadSlice 在找到 delim 之前遇到错误, 则读出缓存中的所有数据并返回,同时返回遇到error(通常是 io.EOF)
    // 如果 在整个缓存中都找不到 delim,则返回 ErrBufferFull
    // 如果 ReadSlice 能找到 delim,则返回 nil
    // 注意: 因为返回的Slice数据有可能被下一次读写操作修改, 因此大多数操作应该使用 ReadBytes 或 ReadString,它们返回数据copy
    // 不推荐!
    inputReadBuf5 := strings.NewReader("中文123 4567 890")
    reader5 := bufio.NewReader(inputReadBuf5)
    for ; ;  {
        b5 , err := reader5.ReadSlice(' ')
        fmt.Println(string(b5))
        // 读到最后
        if err == io.EOF {
            break
        }
    }


    // 9: ReadLine 是一个低级的原始的行读取操作, 一般应该使用 ReadBytes('\n') 或 ReadString('\n')
    // ReadLine 通过调用 ReadSlice 方法实现,返回的也是"引用", 回一行数据,不包括行尾标记(\n 或 \r\n)
    // 如果 在缓存中找不到行尾标记,设置 isPrefix 为 true,表示查找未完成
    // 如果 在当前缓存中找到行尾标记,将 isPrefix 设置为 false,表示查找完成
    // 如果 ReadLine 无法获取任何数据,则返回一个错误信息(通常是 io.EOF)
    // 不推荐!
    inputReadBuf6 := strings.NewReader("中文123\n4567\n890")
    reader6 := bufio.NewReader(inputReadBuf6)
    for ; ;  {
        l, p, err := reader6.ReadLine()
        fmt.Println(string(l), p, err)
        if err == io.EOF {
            break
        }
    }


    // 10: ReadBytes查找 delim 并读出 delim 及其之前的所有数据
    // 如果 ReadBytes 在找到 delim 之前遇到错误, 则返回遇到错误之前的所有数据,同时返回遇到的错误(通常是 io.EOF)
    // 如果 ReadBytes 找不到 delim 时,err != nil
    // 返回的是数据的copy, 不是引用
    inputReadBuf7 := strings.NewReader("中文123;4567;890")
    reader7 := bufio.NewReader(inputReadBuf7)
    for ; ;  {
        line, err := reader7.ReadBytes(';')
        fmt.Println(string(line))
        if err != nil {
            break
        }
    }


    // 11: ReadString返回的是字符串, 不是bytes
    inputReadBuf8 := strings.NewReader("中文123;4567;890")
    reader8 := bufio.NewReader(inputReadBuf8)
    for ; ;  {
        line, err := reader8.ReadString(';')
        fmt.Println(line)
        if err != nil {
            break
        }
    }


    //12: Flush函数用于提交数据, 立即更新
    // Available函数返回缓存中的可以空间
    // b10是保存数据的数组, 不是writer的缓冲区, 别搞错了
    b10 := bytes.NewBuffer(make([]byte, 30))
    // 下面会分配4096字节空间缓冲区
    writer10 := bufio.NewWriter(b10)
    writer10.WriteString("1234567890")
    // 此时没有flush, 那么输出的是"", 但是缓冲区使用了10个字节, 那么剩下4086, Buffered()返回的是缓冲区还没有提交的数据, 此处显然是10
    fmt.Println(writer10.Available(), writer10.Buffered(), b10)
    // 下面flush后, 将缓冲区的数据全部写入b10中, 缓冲区被清空, 所以缓冲区变成4096, Buffered()返回的是0, 说明数据被写入
    writer10.Flush()
    fmt.Println(writer10.Available(), writer10.Buffered(), b10)


    // 13: WriteString(...), Write(...), WriteByte(...), WriteRune(...)函数
    // 都是写数据函数
    b11 := bytes.NewBuffer(make([]byte, 1024))
    writer11 := bufio.NewWriter(b11)
    writer11.WriteString("ABC")
    writer11.WriteByte(byte('M'))
    // Rune的意思是: 代表一个字符, 那么需要一次一个字符写入
    writer11.WriteRune(rune('好'))
    writer11.WriteRune(rune('么'))
    writer11.Write([]byte("1234567890"))
    writer11.Flush()
    fmt.Println(b11)


    // 14: WriteTo函数
    inputReadBuf9 := strings.NewReader("中文1234567890")
    reader9 := bufio.NewReader(inputReadBuf9)
    b9 := bytes.NewBuffer(make([]byte, 0))
    reader9.WriteTo(b9)
    fmt.Println(b9)


    // 15: ReadFrom函数
    inputReadBuf15 := strings.NewReader("率哪来的顺丰内部了第三方吧")
    b15 := bytes.NewBuffer(make([]byte, 0))
    writer15 := bufio.NewWriter(b15)
    writer15.ReadFrom(inputReadBuf15)
    fmt.Println(b15)
}```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容