bytes — byte slice 便利操作
該包定義了一些操作 byte slice 的便利操作。因為字符串可以表示為 []byte,因此,bytes 包定義的函數、方法等和 strings 包很類似,所以講解時會和 strings 包類似甚至可以直接參考。
說明:為了方便,會稱呼 []byte 為 字節數組
byte類型
是否存在某個子 slice
// 子 slice subslice 在 b 中,返回 true func Contains(b, subslice []byte) bool 該函數的內部調用了 bytes.Index 函數(在后面會講解): func Contains(b, subslice []byte) bool { return Index(b, subslice) != -1 }
題外:對比 strings.Contains
你會發現,一個判斷 >=0
,一個判斷 != -1
,可見庫不是一個人寫的,沒有做到一致性。
[]byte 出現次數
// slice sep 在 s 中出現的次數(無重疊) func Count(s, sep []byte) int
和 strings 實現不同,此包中的 Count 核心代碼如下:
count := 0 c := sep[0] i := 0 t := s[:len(s)-n+1] for i < len(t) { // 判斷 sep 第一個字節是否在 t[i:] 中 // 如果在,則比較之后相應的字節 if t[i] != c { o := IndexByte(t[i:], c) if o < 0 { break } i += o } // 執行到這里表示 sep[0] == t[i] if n == 1 || Equal(s[i:i+n], sep) { count++ i += n continue } i++ }
Runes 類型轉換
// 將 []byte 轉換為 []rune func Runes(s []byte) []rune 該函數將 []byte 轉換為 []rune ,適用於漢字等多字節字符,示例: b:=[]byte("你好,世界") for k,v:=range b{ fmt.Printf("%d:%s |",k,string(v)) } r:=bytes.Runes(b) for k,v:=range r{ fmt.Printf("%d:%s|",k,string(v)) } 運行結果: 0:ä |1:½ |2: |3:å |4:¥ |5:½ |6:ï |7:¼ |8: |9:ä |10:¸ |11: |12:ç |13: |14: | 0:你|1:好|2:,|3:世|4:界|
Reader 類型
type Reader struct { s []byte i int64 // 當前讀取下標 prevRune int // 前一個字符的下標,也可能 < 0 }
bytes 包下的 Reader 類型實現了 io 包下的 Reader, ReaderAt, RuneReader, RuneScanner, ByteReader, ByteScanner, ReadSeeker, Seeker, WriterTo 等多個接口。主要用於 Read 數據。
我們需要在通過 bytes.NewReader 方法來初始化 bytes.Reader 類型的對象。初始化時傳入 []byte 類型的數據。NewReader 函數簽名如下:
func NewReader(b []byte) *Reader
如果直接聲明該對象了,可以通過 Reset 方法重新寫入數據,示例:
x:=[]byte("你好,世界") r1:=bytes.NewReader(x) d1:=make([]byte,len(x)) n,_:=r1.Read(d1) fmt.Println(n,string(d1)) r2:=bytes.Reader{} r2.Reset(x) d2:=make([]byte,len(x)) n,_=r2.Read(d2) fmt.Println(n,string(d2))
輸出結果:
15 你好,世界
15 你好,世界
Reader 包含了 8 個讀取相關的方法,實現了前面提到的 io 包下的 9 個接口(ReadSeeker 接口內嵌 Reader 和 Seeker 兩個接口):
// 讀取數據至 b func (r *Reader) Read(b []byte) (n int, err error) // 讀取一個字節 func (r *Reader) ReadByte() (byte, error) // 讀取一個字符 func (r *Reader) ReadRune() (ch rune, size int, err error) // 讀取數據至 w func (r *Reader) WriteTo(w io.Writer) (n int64, err error) // 進度下標指向前一個字節,如果 r.i <= 0 返回錯誤。 func (r *Reader) UnreadByte() // 進度下標指向前一個字符,如果 r.i <= 0 返回錯誤,且只能在每次 ReadRune 方法后使用一次,否則返回錯誤。 func (r *Reader) UnreadRune() // 讀取 r.s[off:] 的數據至b,該方法忽略進度下標 i,不使用也不修改。 func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) // 根據 whence 的值,修改並返回進度下標 i ,當 whence == 0 ,進度下標修改為 off,當 whence == 1 ,進度下標修改為 i+off,當 whence == 2 ,進度下標修改為 len[s]+off. // off 可以為負數,whence 的只能為 0,1,2,當 whence 為其他值或計算后的進度下標越界,則返回錯誤。 func (r *Reader) Seek(offset int64, whence int) (int64, error)
示例:
x := []byte("你好,世界") r1 := bytes.NewReader(x) ch, size, _ := r1.ReadRune() fmt.Println(size, string(ch)) _ = r1.UnreadRune() ch, size, _ = r1.ReadRune() fmt.Println(size, string(ch)) _ = r1.UnreadRune() by, _ := r1.ReadByte() fmt.Println(by) _ = r1.UnreadByte() by, _ = r1.ReadByte() fmt.Println(by) _ = r1.UnreadByte() d1 := make([]byte, 6) n, _ := r1.Read(d1) fmt.Println(n, string(d1)) d2 := make([]byte, 6) n, _ = r1.ReadAt(d2, 0) fmt.Println(n, string(d2)) w1 := &bytes.Buffer{} _, _ = r1.Seek(0, 0) _, _ = r1.WriteTo(w1) fmt.Println(w1.String())
運行結果:
3 你 3 你 228 228 6 你好 6 你好 你好,世界
Buffer 類型
type Buffer struct { buf []byte off int lastRead readOp }
在上一個示例的最后,我們使用了 bytes.Buffer 類型,該類型實現了 io 包下的 ByteScanner, ByteWriter, ReadWriter, Reader, ReaderFrom, RuneReader, RuneScanner, StringWriter, Writer, WriterTo 等接口,可以方便的進行讀寫操作。
對象可讀取數據為 buf[off : len(buf)], off 表示進度下標,lastRead 表示最后讀取的一個字符所占字節數,方便 Unread* 相關操作。
Buffer 可以通過 3 中方法初始化對象:
a := bytes.NewBufferString("Hello World") b := bytes.NewBuffer([]byte("Hello World")) c := bytes.Buffer{} fmt.Println(a) fmt.Println(b) fmt.Println(c) }
輸出結果:
Hello World
Hello World
{[] 0 0}
Buffer 包含了 21 個讀寫相關的方法,大部分同名方法的用法與前面講的類似,這里只講演示其中的 3 個方法:
// 讀取到字節 delim 后,以字節數組的形式返回該字節及前面讀取到的字節。如果遍歷 b.buf 也找不到匹配的字節,則返回錯誤(一般是 EOF) func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) // 讀取到字節 delim 后,以字符串的形式返回該字節及前面讀取到的字節。如果遍歷 b.buf 也找不到匹配的字節,則返回錯誤(一般是 EOF) func (b *Buffer) ReadString(delim byte) (line string, err error) // 截斷 b.buf , 舍棄 b.off+n 之后的數據。n == 0 時,調用 Reset 方法重置該對象,當 n 越界時(n < 0 || n > b.Len() )方法會觸發 panic. func (b *Buffer) Truncate(n int)
示例:
a := bytes.NewBufferString("Good Night") x, err := a.ReadBytes('t') if err != nil { fmt.Println("delim:t err:", err) } else { fmt.Println(string(x)) } a.Truncate(0) a.WriteString("Good Night") fmt.Println(a.Len()) a.Truncate(5) fmt.Println(a.Len()) y, err := a.ReadString('N') if err != nil { fmt.Println("delim:N err:", err) } else { fmt.Println(y) }
輸出結果:
Good Night
10
5
delim:N err: EOF
其它函數
其它大部分函數、方法與 strings 包下的函數、方法類似,只是數據源從 string 變為了 []byte ,請參考 strings 包的用法。
type Buffer
緩沖區是一個可變大小的帶有讀和寫方法的字節緩沖區。Buffer 的零值是一個准備使用的空緩沖區。
func NewBuffer
func NewBuffer(buf []byte) *Buffer
NewBuffer 使用 buf 作為其初始內容創建並初始化新的 Buffer。新的緩沖區取得了 buf 的所有權,並且調用者在調用之后不應該使用 buf 。NewBuffer 旨在准備一個緩沖區來讀取現有數據。它也可以用來調整寫入的內部緩沖區大小。要做到這一點,buf 應該具有所需的容量,但長度為零。
在大多數情況下,新的(緩沖區)(或者只是聲明一個緩沖區變量)足以初始化緩沖區。
func NewBufferString
func NewBufferString(s string) *Buffer
NewBufferString 使用字符串 s 作為其初始內容創建並初始化一個新的 Buffer。它旨在准備一個緩沖區來讀取現有的字符串。
func (*Buffer) Bytes
func (b *Buffer) Bytes() []byte
字節返回一段長度 b.Len(),其中包含緩沖區的未讀部分。該切片僅在下一次緩沖區修改之前有效(即,直到下一次調用 Read,Write,Reset或Truncate 之類的方法)。至少在下一次緩沖區修改之前,切片會對緩沖區內容進行別名,因此切片的即時更改將影響將來讀取的結果。
func (*Buffer) Cap
func (b *Buffer) Cap() int
Cap 返回緩沖區底層字節片段的容量,即分配給緩沖區數據的總空間。
func (*Buffer) Grow
func (b *Buffer) Grow(n int)
如果有必要,增長緩沖區的容量以保證另外n個字節的空間。在Grow(n)之后,至少可以將n個字節寫入緩沖區而無需其他分配。如果n是負數,Grow 會陷入混亂。如果緩沖區不能增長,它會與 ErrTooLarge 一起發生混亂。
func (*Buffer) Len
func (b *Buffer) Len() int
Len 返回緩沖區未讀部分的字節數;b.Len() == len(b.Bytes())。
func (*Buffer) Next
func (b *Buffer) Next(n int) []byte
接下來返回包含來自緩沖區的下n個字節的切片,如同字節已由 Read 返回一樣推進緩沖區。如果緩沖區中少於n個字節,則 Next 返回整個緩沖區。切片只有在下次調用讀取或寫入方法時才有效。
func (*Buffer) Read
func (b *Buffer) Read(p []byte) (n int, err error)
Read 從緩沖區中讀取下一個 len(p) 字節,或者直到緩沖區被耗盡。返回值n是讀取的字節數。如果緩沖區沒有數據要返回,則 err 為 io.EOF(除非len(p)為零); 否則為零。
func (*Buffer) ReadByte
func (b *Buffer) ReadByte() (byte, error)
ReadByte 讀取並返回緩沖區中的下一個字節。如果沒有可用的字節,則返回錯誤 io.EOF。
func (*Buffer) ReadBytes
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
ReadBytes 一直讀取,直到輸入中delim第一次出現時停止 ,並返回一個包含小於等於分隔符數據的片段。如果ReadBytes在查找分隔符之前遇到錯誤,它將返回錯誤之前讀取的數據和錯誤本身(通常為 io.EOF )。當且僅當返回的數據不以分隔符結束時,ReadBytes 才返回 err != nil。
func (*Buffer) ReadFrom
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)
ReadFrom 從 r 讀取數據直到 EOF 並將其附加到緩沖區,根據需要生長緩沖區。返回值n是讀取的字節數。讀取過程中遇到的除 io.EOF 外的任何錯誤也會返回。如果緩沖區變得過大,ReadFrom 將與 ErrTooLarge 一起發生混亂。
func (*Buffer) ReadRune
func (b *Buffer) ReadRune() (r rune, size int, err error)
ReadRune 讀取並返回緩沖區中的下一個UTF-8編碼的 Unicode 代碼點。如果沒有字節可用,返回的錯誤是io.EOF。如果字節是錯誤的UTF-8編碼,則它將消耗一個字節並返回U + FFFD,1。
func (*Buffer) ReadString
func (b *Buffer) ReadString(delim byte) (line string, err error)
ReadString 讀取,直到輸入中第一次出現 delim ,返回一個包含數據的字符串直到並包含分隔符。如果ReadString 在查找分隔符之前遇到錯誤,它將返回在錯誤之前讀取的數據和錯誤本身(通常為 io.EOF )。當且僅當返回的數據沒有以分隔符結束時,ReadString 返回 err!= nil。
func (*Buffer) Reset
func (b *Buffer) Reset()
Reset將緩沖區重置為空,但它保留了未來寫入使用的底層存儲。重置與Truncate(0) 相同。
func (*Buffer) String
func (b *Buffer) String() string
字符串以字符串形式返回緩沖區未讀部分的內容。如果 Buffer 是一個零指針,它將返回“<nil>”。
func (*Buffer) Truncate
func (b *Buffer) Truncate(n int)
截斷從緩沖區丟棄除前 n 個未讀字節以外的所有字節,但繼續使用相同的分配存儲。如果 n 是負數或大於緩沖區的長度,它會發生混亂。
func (*Buffer) UnreadByte
func (b *Buffer) UnreadByte() error
UnreadByte 讀取最近成功讀取操作返回的最后一個字節,該操作至少讀取一個字節。如果自上次讀取后發生寫入,如果上次讀取返回錯誤,或者讀取讀取的是零字節,則 UnreadByte 返回錯誤。
func (*Buffer) UnreadRune
func (b *Buffer) UnreadRune() error
UnreadRune 未讀取 ReadRune 返回的最后一個符文。如果緩沖區上的最新讀取或寫入操作不是成功的ReadRune,則 UnreadRune 將返回錯誤。(在這方面,它比 UnreadByte 更嚴格,它將讀取任何讀操作的最后一個字節。)
func (*Buffer) Write
func (b *Buffer) Write(p []byte) (n int, err error)
寫入將 p 的內容附加到緩沖區,根據需要增加緩沖區。返回值n是 p 的長度; err 總是零。如果緩沖區變得過大,Write 會與 ErrTooLarge 混淆。
func (*Buffer) WriteByte
func (b *Buffer) WriteByte(c byte) error
WriteByte 將字節 c 附加到緩沖區,根據需要生長緩沖區。返回的錯誤始終為零,但包含在內以匹配
bufio.Writer 的 WriteByte 。如果緩沖區變得太大,WriteByte 會與 ErrTooLarge 一起發生混亂。
func (*Buffer) WriteRune
func (b *Buffer) WriteRune(r rune) (n int, err error)
WriteRune 將 Unicode 代碼點 r 的UTF-8 編碼附加到緩沖區,返回其長度和錯誤,該錯誤總是為零,但包含在內以匹配 bufio.Writer 的 WriteRune。緩沖區根據需要增長;如果它變得太大,WriteRune 將會與 ErrTooLarge 混淆。
func (*Buffer) WriteString
func (b *Buffer) WriteString(s string) (n int, err error)
WriteString將 s 的內容附加到緩沖區,根據需要增加緩沖區。返回值 n 是 s 的長度;err 總是零。如果緩沖區變得太大,WriteString 會與 ErrTooLarge 混淆。
func (*Buffer) WriteTo
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)
WriteTo 將數據寫入 w 直到緩沖區耗盡或發生錯誤。返回值n是寫入的字節數;它總是適合 int ,但它是
int64 來匹配 io.WriterTo 接口。寫入過程中遇到的任何錯誤也會返回。
type Reader
Reader 通過從字節片段讀取來實現 io.Reader,io.ReaderAt,io.WriterTo,io.Seeker,io.ByteScanner和io.RuneScanner 接口。與緩沖區不同,Reader 是只讀的並支持搜索。
type Reader struct {
// 包含過濾或未導出的字段
}
func NewReader
func NewReader(b []byte) *Reader
NewReader從 b 返回新的 Reader 讀數。
func (*Reader) Len
func (r *Reader) Len() int
Len 返回切片的未讀部分的字節數。
func (*Reader) Read
func (r *Reader) Read(b []byte) (n int, err error)
func (*Reader) ReadAt
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)
func (*Reader) ReadByte
func (r *Reader) ReadByte() (byte, error
)
func (*Reader) ReadRune
func (r *Reader) ReadRune() (ch rune, size int, err error)
func (*Reader) Reset
func (r *Reader) Reset(b []byte)
Reset 將Reader(讀取器)重置為從 b 中讀取。
func (*Reader) Seek
func (r *Reader) Seek(offset int64, whence int) (int64, error)
Seek 實現了 io.Seeker 接口。
func (*Reader) Size
func (r *Reader) Size() int64
Size 返回基礎字節片的原始長度。大小是可通過 ReadAt 讀取的字節數。返回的值總是相同的,不受調用任何其他方法的影響。
func (*Reader) UnreadByte
func (r *Reader) UnreadByte() error
func (*Reader) UnreadRune
func (r *Reader) UnreadRune() error
func (*Reader) WriteTo
func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
WriteTo 實現 io.WriterTo 接口。