go原生庫(kù)的中bytes.Buffer用法
1 bytes.Buffer定義
bytes.Buffer提供可擴(kuò)容的字節(jié)緩沖區(qū),實(shí)質(zhì)是對(duì)切片的封裝;結(jié)構(gòu)中包含一個(gè)64字節(jié)的小切片,避免小內(nèi)存分配:
// A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)]--->指示讀指針 bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. lastRead readOp // last read operation, so that Unread* can work correctly. }
2 初始化bytes.Buffer的方法
1) var buf bytes.Buffer ->定義一個(gè)空的字節(jié)緩沖區(qū)
2) func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } -->將字節(jié)切片初始化為緩沖區(qū)
3) func NewBufferString(s string) *Buffer {return &Buffer{buf: []byte(s)}} -->將字符串初始化為緩沖區(qū)
3 提供的主要API函數(shù)
1)寫字節(jié)流數(shù)據(jù)到緩沖區(qū)
// Write appends the contents of p to the buffer, growing the buffer as // needed. The return value n is the length of p; err is always nil. If the // buffer becomes too large, Write will panic with ErrTooLarge. func (b *Buffer) Write(p []byte) (n int, err error) { b.lastRead = opInvalid m := b.grow(len(p)) return copy(b.buf[m:], p), nil }
2)寫字符串到緩沖區(qū)
// WriteString appends the contents of s to the buffer, growing the buffer as // needed. The return value n is the length of s; err is always nil. If the // buffer becomes too large, WriteString will panic with ErrTooLarge. func (b *Buffer) WriteString(s string) (n int, err error) { b.lastRead = opInvalid //返回寫入的index m := b.grow(len(s)) return copy(b.buf[m:], s), nil }
3)從緩沖區(qū)中讀取數(shù)據(jù)
// Read reads the next len(p) bytes from the buffer or until the buffer // is drained. The return value n is the number of bytes read. If the // buffer has no data to return, err is io.EOF (unless len(p) is zero); // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) if len(p) == 0 { return } return 0, io.EOF } n = copy(p, b.buf[b.off:]) b.off += n if n > 0 { b.lastRead = opRead } return }
4)從緩沖區(qū)中讀取字符串,直到分隔符delim 位置
// ReadString reads until the first occurrence of delim in the input, // returning a string containing the data up to and including the delimiter. // If ReadString encounters an error before finding a delimiter, // it returns the data read before the error and the error itself (often io.EOF). // ReadString returns err != nil if and only if the returned data does not end // in delim. func (b *Buffer) ReadString(delim byte) (line string, err error) { slice, err := b.readSlice(delim) return string(slice), err }
5)將未被讀取的字節(jié)數(shù)據(jù)返回
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer. // The slice is valid for use only until the next buffer modification (that is, // only until the next call to a method like Read, Write, Reset, or Truncate). // The slice aliases the buffer content at least until the next buffer modification, // so immediate changes to the slice will affect the result of future reads. func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
6)將未被讀取的字節(jié)數(shù)據(jù)以字符串形式返回
// String returns the contents of the unread portion of the buffer // as a string. If the Buffer is a nil pointer, it returns "<nil>". func (b *Buffer) String() string { if b == nil { // Special case, useful in debugging. return "<nil>" } return string(b.buf[b.off:]) }
7)返回緩沖區(qū)當(dāng)前容量
// Cap returns the capacity of the buffer's underlying byte slice, that is, the // total space allocated for the buffer's data. func (b *Buffer) Cap() int { return cap(b.buf) }
8)返回未被讀取的字節(jié)數(shù)據(jù)大小
// Len returns the number of bytes of the unread portion of the buffer; // b.Len() == len(b.Bytes()). func (b *Buffer) Len() int { return len(b.buf) - b.off }
4 bytes.Buffer自動(dòng)擴(kuò)容機(jī)制
當(dāng)向緩沖區(qū)寫入數(shù)據(jù)時(shí),首先會(huì)檢查當(dāng)前容量是否滿足需求,如果不滿足分三種情況處理:
1)當(dāng)前內(nèi)置緩沖區(qū)切片buf為空,且寫入數(shù)據(jù)量小于bootstrap的大小(64字節(jié)),則bootstrap作為buf
2)當(dāng)前未讀數(shù)據(jù)長(zhǎng)度+新寫入數(shù)據(jù)長(zhǎng)度小于等于緩沖區(qū)容量的1/2,則挪動(dòng)數(shù)據(jù)(將未讀的數(shù)據(jù)放到已讀數(shù)據(jù)位置)
3)以上條件不滿足,只能重新分配切片,容量設(shè)定為2*cap(b.buf) + n,即兩倍原來(lái)的緩沖區(qū)容量+寫入數(shù)據(jù)量大小
// grow grows the buffer to guarantee space for n more bytes. // It returns the index where bytes should be written. // If the buffer can't grow it will panic with ErrTooLarge. func (b *Buffer) grow(n int) int { m := b.Len() // If buffer is empty, reset to recover space. if m == 0 && b.off != 0 { b.Truncate(0) } //如果需要的容量大于現(xiàn)在的容量---> if len(b.buf)+n > cap(b.buf) { var buf []byte //現(xiàn)有的預(yù)備64byte可以滿足 if b.buf == nil && n <= len(b.bootstrap) { buf = b.bootstrap[0:] //實(shí)際需要的小于本身切片容量 } else if m+n <= cap(b.buf)/2 { // We can slide things down instead of allocating a new // slice. We only need m+n <= cap(b.buf) to slide, but // we instead let capacity get twice as large so we // don't spend all our time copying. copy(b.buf[:], b.buf[b.off:]) buf = b.buf[:m] } else { // not enough space anywhere //不夠,那就分配2倍加n的容量 buf = makeSlice(2*cap(b.buf) + n) copy(buf, b.buf[b.off:]) } b.buf = buf b.off = 0 } b.buf = b.buf[0 : b.off+m+n] return b.off + m }
5 bytes.Buffer的局限
bytes.Buffer提供了對(duì)切片的初步封裝,但也沒做太多的事;對(duì)于已讀的數(shù)據(jù)無(wú)法操作。
補(bǔ)充:Golang bytes.Buffer 用法精述
1.簡(jiǎn)介
bytes.Buffer 是 Golang 標(biāo)準(zhǔn)庫(kù)中的緩沖區(qū),具有讀寫方法和可變大小的字節(jié)存儲(chǔ)功能。緩沖區(qū)的零值是一個(gè)待使用的空緩沖區(qū)。
定義如下:
type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] lastRead readOp // last read operation, so that Unread* can work correctly. }
注意要點(diǎn):
(1)從 bytes.Buffer 讀取數(shù)據(jù)后,被成功讀取的數(shù)據(jù)仍保留在原緩沖區(qū),只是無(wú)法被使用,因?yàn)榫彌_區(qū)的可見數(shù)據(jù)從偏移 off 開始,即buf[off : len(buf)]。
2.常用方法
(1)聲明一個(gè) Buffer
var b bytes.Buffer //直接定義一個(gè)Buffer變量,不用初始化,可以直接使用 b := new(bytes.Buffer) //使用New返回Buffer變量 b := bytes.NewBuffer(s []byte) //從一個(gè)[]byte切片,構(gòu)造一個(gè)Buffer b := bytes.NewBufferString(s string) //從一個(gè)string變量,構(gòu)造一個(gè)Buffer
(2)往 Buffer 中寫入數(shù)據(jù)
b.Write(d []byte) (n int, err error) //將切片d寫入Buffer尾部 b.WriteString(s string) (n int, err error) //將字符串s寫入Buffer尾部 b.WriteByte(c byte) error //將字符c寫入Buffer尾部 b.WriteRune(r rune) (n int, err error) //將一個(gè)rune類型的數(shù)據(jù)放到緩沖區(qū)的尾部 b.ReadFrom(r io.Reader) (n int64, err error) //從實(shí)現(xiàn)了io.Reader接口的可讀取對(duì)象寫入Buffer尾部
(3)從 Buffer 中讀取數(shù)據(jù)
//讀取 n 個(gè)字節(jié)數(shù)據(jù)并返回,如果 buffer 不足 n 字節(jié),則讀取全部 b.Next(n int) []byte //一次讀取 len(p) 個(gè) byte 到 p 中,每次讀取新的內(nèi)容將覆蓋p中原來(lái)的內(nèi)容。成功返回實(shí)際讀取的字節(jié)數(shù),off 向后偏移 n,buffer 沒有數(shù)據(jù)返回錯(cuò)誤 io.EOF b.Read(p []byte) (n int, err error) //讀取第一個(gè)byte并返回,off 向后偏移 n b.ReadByte() (byte, error) //讀取第一個(gè) UTF8 編碼的字符并返回該字符和該字符的字節(jié)數(shù),b的第1個(gè)rune被拿掉。如果buffer為空,返回錯(cuò)誤 io.EOF,如果不是UTF8編碼的字符,則消費(fèi)一個(gè)字節(jié),返回 (U+FFFD,1,nil) b.ReadRune() (r rune, size int, err error) //讀取緩沖區(qū)第一個(gè)分隔符前面的內(nèi)容以及分隔符并返回,緩沖區(qū)會(huì)清空讀取的內(nèi)容。如果沒有發(fā)現(xiàn)分隔符,則返回讀取的內(nèi)容并返回錯(cuò)誤io.EOF b.ReadBytes(delimiter byte) (line []byte, err error) //讀取緩沖區(qū)第一個(gè)分隔符前面的內(nèi)容以及分隔符并作為字符串返回,緩沖區(qū)會(huì)清空讀取的內(nèi)容。如果沒有發(fā)現(xiàn)分隔符,則返回讀取的內(nèi)容并返回錯(cuò)誤 io.EOF b.ReadString(delimiter byte) (line string, err error) //將 Buffer 中的內(nèi)容輸出到實(shí)現(xiàn)了 io.Writer 接口的可寫入對(duì)象中,成功返回寫入的字節(jié)數(shù),失敗返回錯(cuò)誤 b.WriteTo(w io.Writer) (n int64, err error)
(4)其它操作
b.Bytes() []byte //返回字節(jié)切片 b.Cap() int //返回 buffer 內(nèi)部字節(jié)切片的容量 b.Grow(n int) //為 buffer 內(nèi)部字節(jié)切片的容量增加 n 字節(jié) b.Len() int //返回緩沖區(qū)數(shù)據(jù)長(zhǎng)度,等于 len(b.Bytes()) b.Reset() //清空數(shù)據(jù) b.String() string //字符串化 b.Truncate(n int) //丟棄緩沖區(qū)中除前n個(gè)未讀字節(jié)以外的所有字節(jié)。如果 n 為負(fù)數(shù)或大于緩沖區(qū)長(zhǎng)度,則引發(fā) panic b.UnreadByte() error //將最后一次讀取操作中被成功讀取的字節(jié)設(shè)為未被讀取的狀態(tài),即將已讀取的偏移 off 減 1 b.UnreadRune() error //將最后一次 ReadRune() 讀取操作返回的 UTF8 字符 rune設(shè)為未被讀取的狀態(tài),即將已讀取的偏移 off 減去 字符 rune 的字節(jié)數(shù)
3.使用示例
(1)從文件 test.txt 中讀取全部?jī)?nèi)容追加到 buffer 尾部
test.txt 的內(nèi)容為:
My name is dablelv
具體實(shí)現(xiàn):
package main import ( "os" "fmt" "bytes" ) func main() { file, _ := os.Open("./test.txt") buf := bytes.NewBufferString("Hello world ") buf.ReadFrom(file) //將text.txt內(nèi)容追加到緩沖器的尾部 fmt.Println(buf.String()) }
編譯運(yùn)行輸出:
Hello world My name is dablelv
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Golang中常見的三種并發(fā)控制方式使用小結(jié)
這篇文章主要為大家詳細(xì)介紹了如何對(duì)goroutine并發(fā)行為的控制,在Go中最常見的有三種方式:sync.WaitGroup、channel和Context,下面我們就來(lái)看看他們的具體使用吧2024-01-01Fedora14 Linux系統(tǒng)安裝Golang開發(fā)環(huán)境筆記
這篇文章主要介紹了Fedora14 Linux系統(tǒng)安裝Golang開發(fā)環(huán)境筆記,本文講解了2種安裝方法,需要的朋友可以參考下2014-10-10Go語(yǔ)言將string解析為time.Time時(shí)兩種常見報(bào)錯(cuò)
本文主要介紹了Go語(yǔ)言將string解析為time.Time時(shí)兩種常見報(bào)錯(cuò),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03如何用golang運(yùn)行第一個(gè)項(xiàng)目
這篇文章主要介紹了如何用golang運(yùn)行第一個(gè)項(xiàng)目,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Go實(shí)現(xiàn)分布式唯一ID的生成之雪花算法
本文主要介紹了Go實(shí)現(xiàn)分布式唯一ID的生成之雪花算法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Golang中的sync.WaitGroup用法實(shí)例
這篇文章主要介紹了Golang中的sync.WaitGroup用法實(shí)例,WaitGroup的用途,它能夠一直等到所有的goroutine執(zhí)行完成,并且阻塞主線程的執(zhí)行,直到所有的goroutine執(zhí)行完成,需要的朋友可以參考下2015-07-07