golang之bufio包的使用


原文地址:http://www.niu12.com/article/38

github地址:https://github.com/ZQCard/go_api_practice

// 參考:https://www.cnblogs.com/golove/p/3282667.html
// bufio 包實現了帶緩存的 I/O 操作
// 它封裝一個 io.Reader 或 io.Writer 對象
// 使其具有緩存和一些文本讀寫功能
package main

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

func main() {
// TestPeek()
// TestRead()
// TestBuffered()
// TestReadByte()
// TestUnreadByte()
// TestReadRune()
// TestUnReadRune()
// TestReadLine()
// TestReadBytes()
// TestReadString()
// TestWriteTo()
// TestNewWriter()
// TestWrite()
// TestWriteString()
// TestWriteByte()
// TestWriteRune()
// TestReadFrom()
// TestReadWriter()
// TestNewScanner()
// TestSplit()
// TestScan()
// TestScanBytes()
// TestScanRunes()
// TestScanWords()
// TestScanLines()
}

func TestPeek() {
/*
func NewReaderSize(rd io.Reader, size int) *Reader
NewReaderSize 將 rd 封裝成一個帶緩存的 bufio.Reader 對象,
緩存大小由 size 指定(如果小於 16 則會被設置為 16)。
minReadBufferSize = 16
如果 rd 的基類型就是有足夠緩存的 bufio.Reader 類型,則直接將
rd 轉換為基類型返回。

NewReader()方法返回一個默認大小的帶緩存的bufio.Reader對象
即 NewReaderSize(rd, 4096)
*/
s := strings.NewReader("hello world")

// func (b *Reader) Reset(r io.Reader)
// Reset丟棄緩沖中的數據,清除任何錯誤,將b重設為其下層從r讀取數據。
s.Reset("my name is card")

// func (b *Reader) Peek(n int) ([]byte, error)
// Peek 返回緩存的一個切片,該切片引用緩存中前 n 個字節的數據,
// 該操作不會將數據讀出,只是引用,引用的數據在下一次讀取操作之
// 前是有效的。如果切片長度小於 n,則返回一個錯誤信息說明原因。
// 如果 n 大於緩存的總大小,則返回 ErrBufferFull。
br := bufio.NewReader(s)

b, _ := br.Peek(5)
b[0] = 'a'
b, _ = br.Peek(5)
fmt.Printf("%q\n", b) // "ay na"
}

func TestRead() {
// Read 從 b 中讀出數據到 p 中,返回寫入p的字節數
// 讀取到達結尾時,返回值n將為0而err將為io.EOF。
// 如果緩存不為空,則只能讀出緩存中的數據,不會從底層 io.Reader
// 中提取數據,如果緩存為空,則:
// 1、len(p) >= 緩存大小,則跳過緩存,直接從底層 io.Reader 中讀
// 出到 p 中。
// 2、len(p) < 緩存大小,則先將數據從底層 io.Reader 中讀取到緩存
// 中,再從緩存讀取到 p 中。
// func (b *Reader) Read(p []byte) (n int, err error)
s := strings.NewReader("123456789")
br := bufio.NewReader(s)
b := make([]byte, 4)
n, err := br.Read(b)
fmt.Printf("%s %v %v\n", b[:n], n, err) // 1234 4

n, err = br.Read(b)
fmt.Printf("%s %v %v\n", b[:n], n, err) // 5678 4

n, err = br.Read(b)
fmt.Printf("%s %v %v\n", b[:n], n, err) // 9 1

n, err = br.Read(b)
fmt.Printf("%s %v %v\n", b[:n], n, err) // 0 EOF
}

func TestBuffered() {
// 返回可以從緩存中讀取的字節數
// func (b *Reader) Buffered() int { return b.w - b.r }
s := strings.NewReader("123456789")
br := bufio.NewReader(s)
b := make([]byte, 3)
br.Read(b)
fmt.Println(br.Buffered()) // 6

br.Read(b)
fmt.Println(br.Buffered()) // 3
}

func TestReadByte() {
// ReadByte讀取並返回一個字節。如果沒有可用的數據,會返回錯誤。
// func (b *Reader) ReadByte() (c byte, err error)
origin := "abcd"
s := strings.NewReader(origin)
br := bufio.NewReader(s)
// 第一次讀取
tmp, err := br.ReadByte()
if err != nil {
panic(err)
}
fmt.Printf("%q\n", tmp) // 'a'
fmt.Println(br.Buffered()) // 3
for i := 0; i < len(origin); i++ {
tmp, err = br.ReadByte()
if err != nil {          // panic: EOF 因為已經讀取了1個字符 緩存中只剩下3個 // 所以在讀取第4個字符報錯EOF  
panic(err)
}
}
}

func TestUnreadByte() {
// 撤消最后讀出的字節
s := strings.NewReader("abcde")
br := bufio.NewReader(s)
tmp, _ := br.ReadByte()
fmt.Printf("%q\n", tmp) // 'a'
fmt.Println(br.Buffered()) // 4
br.UnreadByte() // 撤銷吐出,即棧中彈出的a元素又放回來了
fmt.Println(br.Buffered()) // 5
tmp, _ = br.ReadByte()
fmt.Printf("%q\n", tmp) // 'a'
}

func TestReadRune() {
// ReadRune讀取一個utf-8編碼的unicode碼值
chinese := "中國人"
s := strings.NewReader(chinese)
br := bufio.NewReader(s)
tmp, _, err := br.ReadRune()
if err != nil {
panic(err)
}
fmt.Printf("%q\n", tmp) // '中'
}

func TestUnReadRune() {
chinese := "中國人"
s := strings.NewReader(chinese)
br := bufio.NewReader(s)
tmp, _, err := br.ReadRune()
if err != nil {
panic(err)
}
fmt.Printf("%q\n", tmp) // '中'
br.UnreadRune()
tmp, _, err = br.ReadRune()
if err != nil {
panic(err)
}
fmt.Printf("%q\n", tmp) // '中'
}

func TestReadLine() {
// ReadLine 是一個低水平的行讀取原語,大多數情況下,應該使用
// ReadBytes('\n') 或 ReadString('\n'),或者使用一個 Scanner。
//
// ReadLine 通過調用 ReadSlice 方法實現,返回的也是緩存的切片。用於
// 讀取一行數據,不包括行尾標記(\n 或 \r\n)。
//
// 只要能讀出數據,err 就為 nil。如果沒有數據可讀,則 isPrefix 返回
// false,err 返回 io.EOF。
//
// 如果找到行尾標記,則返回查找結果,isPrefix 返回 false。
// 如果未找到行尾標記,則:
// 1、緩存不滿,則將緩存填滿后再次查找。
// 2、緩存是滿的,則返回整個緩存,isPrefix 返回 true。
//
// 整個數據尾部“有一個換行標記”和“沒有換行標記”的讀取結果是一樣。
//
// 如果 ReadLine 讀取到換行標記,則調用 UnreadByte 撤銷的是換行標記,
// 而不是返回的數據。
// func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)

s := strings.NewReader("123\nzzz")
br := bufio.NewReader(s)
for line, isPrefix, err := []byte{0}, false, error(nil);        len(line) > 0 && err == nil; {
line, isPrefix, err = br.ReadLine()
// "123" false
// "zzz" false
// "" false EOF
fmt.Printf("%q %t %v\n", line, isPrefix, err)
}
}

func TestReadSlice() {
// ReadSlice 在 b 中查找 delim 並返回 delim 及其之前的所有數據。
// 該操作會讀出數據,返回的切片是已讀出的數據的引用,切片中的數據
// 在下一次讀取操作之前是有效的。
//
// 如果找到 delim,則返回查找結果,err 返回 nil。
// 如果未找到 delim,則:
// 1、緩存不滿,則將緩存填滿后再次查找。
// 2、緩存是滿的,則返回整個緩存,err 返回 ErrBufferFull。
//
// 如果未找到 delim 且遇到錯誤(通常是 io.EOF),則返回緩存中的所
// 有數據和遇到的錯誤。
//
// 因為返回的數據有可能被下一次的讀寫操作修改,所以大多數操作應該
// 使用 ReadBytes 或 ReadString,它們返回的是數據的拷貝。
// func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
s := strings.NewReader("ABC DEF GHI")
br := bufio.NewReader(s)

w, err := br.ReadSlice(' ')
if err != nil {
panic(err)
}
fmt.Printf("%q\n", w) // "ABC "

w, err = br.ReadSlice(' ')
if err != nil {
panic(err)
}
fmt.Printf("%q\n", w) // "DEF "

w, err = br.ReadSlice(' ')
if err != nil {
panic(err)
}
fmt.Printf("%q\n", w) // panic: EOF
}

func TestReadBytes() {
// ReadBytes 功能同 ReadSlice,只不過返回的是緩存的拷貝。
// func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
s := strings.NewReader("ABC,EFG,HIJ")
br := bufio.NewReader(s)
line, err := br.ReadBytes(',')
if err != nil {
panic(err)
}
fmt.Printf("%q\n", line) // "ABC,"

line, err = br.ReadBytes(',')
if err != nil {
panic(err)
}
fmt.Printf("%q\n", line) // "EFG,"

line, err = br.ReadBytes(',')
if err != nil {
panic(err) // panic: EOF
}
fmt.Printf("%q\n", line)

}

func TestReadString() {
// ReadString 功能同 ReadBytes,只不過返回的是字符串。
// func (b *Reader) ReadString(delim byte) (line string, err error)
s := strings.NewReader("你好,我是卡牌")
br := bufio.NewReader(s)
line, err := br.ReadString(',')
if err != nil {
panic(err)
}
fmt.Printf("%s\n", line) // 你好,

line, err = br.ReadString(',')
if err != nil {
panic(err) // panic: EOF
}
fmt.Printf("%s\n", line)
}

func TestWriteTo() {
// WriteTo方法實現了io.WriterTo接口。
// func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
s := strings.NewReader("ABCDEFG")
br := bufio.NewReader(s)
b := bytes.NewBuffer(make([]byte, 0))
br.WriteTo(b)
fmt.Printf("%q\n", b) // "ABCDEFG"
}

// Writer實現了為io.Writer接口對象提供緩沖。
// 如果在向一個Writer類型值寫入時遇到了錯誤,
// 該對象將不再接受任何數據,返回該錯誤
// 數據都寫入后,調用者有義務調用Flush方法,
// 保證所有的數據都交給了下層的io.Writer。
func TestNewWriter() {

// NewWriter創建一個具有默認大小緩沖、寫入w的*Writer。
// 相當於 NewWriterSize(wr, 4096)
// func NewWriter(w io.Writer) *Writer

// Buffered()返回緩沖中已使用的字節數。
// func (b *Writer) Buffered() int

// Available()返回緩沖中還有多少字節未使用。
// func (b *Writer) Available() int

// Reset丟棄緩沖中的數據,清除任何錯誤,將b重設為將其輸出寫入w。
// func (b *Writer) Reset(w io.Writer)

b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)

fmt.Println(bw.Available(), bw.Buffered()) // 4096 0
bw.WriteString("card")
fmt.Println(bw.Available(), bw.Buffered()) // 4092 4

bw.Reset(b)
fmt.Println(bw.Available(), bw.Buffered()) // 4096 0
}

func TestWrite() {
// Write 將 p 中的數據寫入 b 中,返回寫入的字節數
// 如果寫入的字節數小於 p 的長度,則返回一個錯誤信息
// func (b *Writer) Write(p []byte) (nn int, err error)

// Flush 將緩存中的數據提交到底層的 io.Writer 中
// func (b *Writer) Flush() error
p := [...]byte{'a', 'b', 'c'}
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.Write(p[:])
bw.Flush()
fmt.Printf("%q\n", b)
}

func TestWriteString() {
// WriteString 同 Write,只不過寫入的是字符串
// func (b *Writer) WriteString(s string) (int, error)
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.WriteString("hello world")
bw.Flush()
fmt.Printf("%s\n", b)
}

func TestWriteByte() {
// WriteByte寫入單個字節。
// func (b *Writer) WriteByte(c byte) error
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
bw.WriteByte('c')
bw.Flush()
fmt.Println(b)
}

func TestWriteRune() {
// WriteRune寫入一個unicode碼值(的utf-8編碼),返回寫入的字節數和可能的錯誤。
// func (b *Writer) WriteRune(r rune) (size int, err error)
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
size, err := bw.WriteRune('周')
if err != nil {
panic(err)
}
fmt.Println(size) // 3
bw.Flush()
fmt.Println(b) // 周
}

func TestReadFrom() {
// ReadFrom實現了io.ReaderFrom接口。
// func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)
// ReadFrom無需使用Flush
b := bytes.NewBuffer(make([]byte, 0))
s := strings.NewReader("hello world")
bw := bufio.NewWriter(b)
bw.ReadFrom(s)
fmt.Println(b)
}

func TestReadWriter() {
// ReadWriter類型保管了指向Reader和Writer類型的指針
// 實現了io.ReadWriter接口。

// NewReadWriter 生成bufio.ReadWriter對象
// func NewReadWriter(r *Reader, w *Writer) *ReadWriter
b := bytes.NewBuffer(make([]byte, 0))
bw := bufio.NewWriter(b)
s := strings.NewReader("hello world")
br := bufio.NewReader(s)
rw := bufio.NewReadWriter(br, bw)

word, err := rw.ReadString(' ')
if err != nil {
panic(err)
}
fmt.Printf("%s\n", word) // hello

_, err = rw.WriteString(",I'm coming")
if err != nil {
panic(err)
}
rw.Flush()
fmt.Println(b)
}

func TestNewScanner() {
// Scanner 提供了一個方便的接口來讀取數據,例如遍歷多行文本中的行。Scan 方法會通過
// 一個“匹配函數”讀取數據中符合要求的部分,跳過不符合要求的部分。“匹配函數”由調
// 用者指定。本包中提供的匹配函數有“行匹配函數”、“字節匹配函數”、“字符匹配函數”
// 和“單詞匹配函數”,用戶也可以自定義“匹配函數”。默認的“匹配函數”為“行匹配函
// 數”,用於獲取數據中的一行內容(不包括行尾標記)
//
// Scanner 使用了緩存,所以匹配部分的長度不能超出緩存的容量。默認緩存容量為 4096 -
// bufio.MaxScanTokenSize,用戶可以通過 Buffer 方法指定自定義緩存及其最大容量。
//
// Scan 在遇到下面的情況時會終止掃描並返回 false(掃描一旦終止,將無法再繼續):
// 1、遇到 io.EOF
// 2、遇到讀寫錯誤
// 3、“匹配部分”的長度超過了緩存的長度
//
// 如果需要對錯誤進行更多的控制,
// 或“匹配部分”超出緩存容量,或需要連續掃描,
// 則應該使用 bufio.Reader
// func NewScanner(r io.Reader) *Scanner

// Bytes方法返回最近一次Scan調用生成的token。
// 底層數組指向的數據可能會被下一次Scan的調用重寫。
// func (s *Scanner) Bytes() []byte


// Buffer()方法設置掃描時使用的初始緩沖區和最大值
// 默認情況下,Scan使用內部緩沖區並設置MaxScanTokenSize的最大令牌大小
s := strings.NewReader("周起\n卡牌\n程序員\n")
bs := bufio.NewScanner(s)
bs.Buffer(make([]byte,0),bufio.MaxScanTokenSize)
for bs.Scan() {
// 周起
// 卡牌
// 程序員
fmt.Printf("%s\n", bs.Bytes())
}
}

func TestSplit() {
// Split設置該Scanner的分割函數。默認設置為 bufio.ScanLines()
// 本方法必須在Scan之前調用。
// func (s *Scanner) Split(split SplitFunc)
s := strings.NewReader("周起 卡牌 程序員")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)

// Text返回由Scan調用生成的最新標記,
// 作為保存其字節的新分配字符串。

for bs.Scan() {
fmt.Printf("%s\n", bs.Text())
}
}

func TestScan() {
// Scan方法獲取當前位置的token(該token可以通過Bytes或Text方法獲得),
// 並讓Scanner的掃描位置移動到下一個token。
// 當掃描因為抵達輸入流結尾或者遇到錯誤而停止時,
// 本方法會返回false。在Scan方法返回false后,
// Err方法將返回掃描時遇到的任何錯誤;
// 除非是io.EOF,此時Err會返回nil。
// func (s *Scanner) Scan() bool
s := strings.NewReader("周起 卡牌 程序員")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan() {
fmt.Printf("%s %s\n", bs.Text(), bs.Bytes())
}
}

func TestScanBytes() {
// Bytes方法返回最近一次Scan調用生成的token。
// 底層數組指向的數據可能會被下一次Scan的調用重寫。
s := strings.NewReader("abcd")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanBytes)
for bs.Scan(){
// a
// b
// c
// d
fmt.Printf("%s\n", bs.Bytes())
}
}

func TestScanRunes() {
// ScanRunes是用於Scanner類型的分割函數(符合SplitFunc),
// 本函數會將每個utf-8編碼的unicode碼值作為一個token返回。
s := strings.NewReader("周起卡牌程序員")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanRunes)
for bs.Scan() {
// 周
// 起
// 卡
// 牌
// 程
// 序
// 員
fmt.Printf("%s\n", bs.Text())
}
}

func TestScanWords() {
// ScanRunes是用於Scanner類型的分割函數(符合SplitFunc),
// 本函數會將空白(參見unicode.IsSpace)
// 分隔的片段(去掉前后空白后)作為一個token返回。
// 本函數永遠不會返回空字符串。
s := strings.NewReader("我 是 卡 牌")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanWords)
for bs.Scan(){
// 我
// 是
// 卡
// 牌
fmt.Printf("%s\n", bs.Text())
}
}

func TestScanLines() {
// 將每一行文本去掉末尾的換行標記作為一個token返回
// 此函數的bs.Scan()的默認值
s := strings.NewReader("卡牌\n周起\n程序員\n")
bs := bufio.NewScanner(s)
bs.Split(bufio.ScanLines)
for bs.Scan(){
// 卡牌
// 周起
// 程序員
fmt.Printf("%s\n", bs.Text())
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM