zoukankan      html  css  js  c++  java
  • go bytes — byte slice 便利操作

    原文链接

    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 接口。

  • 相关阅读:
    面试收集—hello,world 也有新花样
    div+css优缺点
    css固定textarea文本域尺寸
    Python if __name__ == "__main__":
    ActionScript3.0基础教程
    【转】Flex代码生成器 (FCG)
    手机第一博文
    TabNavigator只初始化第一个TAB 引发的未初始化对象错误
    如何对待懒惰的小孩
    对孩子真诚就是尊重孩子,不要随意表扬
  • 原文地址:https://www.cnblogs.com/-wenli/p/12354516.html
Copyright © 2011-2022 走看看