首页 > 其他分享 >go库bytes

go库bytes

时间:2024-01-24 12:23:04浏览次数:29  
标签:fmt bytes Println func go byte buf

bytes

strings的基本操作与bytes的基本操作基本类似 

基本操作

比较

和比较相关的方法有:

  • func Equal(a, b []byte) bool
  • func EqualFold(s, t []byte) bool
  • func Compare(a, b []byte) int

其中EqualCompare是使用汇编来实现的。

例如:

a := []byte("hello")
b := []byte("world")
fmt.Println(bytes.Equal(a, b))   // false
fmt.Println(bytes.Compare(a, b)) // -1
fmt.Println(bytes.Compare(b, a)) // 1

EqualFold会忽略大小写,同时会将特殊字符进行转换。例如:

a := []byte("hello ϕ")
b := []byte("Hello Φ")
fmt.Println(bytes.EqualFold(a, b)) // true

index

和index相关的方法有:

  • func Index(s, sep []byte) int
  • func IndexAny(s []byte, chars string) int
  • func IndexByte(s []byte, c byte) int
  • func IndexFunc(s []byte, f func(r rune) bool) int
  • func IndexRune(s []byte, r rune) int
  • func LastIndex(s, sep []byte) int
  • func LastIndexAny(s []byte, chars string) int
  • func LastIndexByte(s []byte, c byte) int
  • func LastIndexFunc(s []byte, f func(r rune) bool) int

例如:

s := []byte("Hello 世界")
fmt.Println(bytes.Index(s, []byte("llo"))) // 2
fmt.Println(bytes.IndexAny(s, "ole"))      // 1
fmt.Println(bytes.IndexByte(s, 'l'))       // 2
fmt.Println(bytes.IndexRune(s, '界'))       // 9

包含

和包含相关的方法有:

  • func Contains(b, subslice []byte) bool
  • func ContainsAny(b []byte, chars string) bool
  • func ContainsRune(b []byte, r rune) bool
  • func Count(s, sep []byte) int
  • func HasPrefix(s, prefix []byte) bool
  • func HasSuffix(s, suffix []byte) bool

例如:

s := []byte("Hello 世界")
fmt.Println(bytes.Contains(s, []byte("llo"))) // true
fmt.Println(bytes.ContainsAny(s, "llo"))      // true
fmt.Println(bytes.ContainsRune(s, '世'))       // true
fmt.Println(bytes.Count(s, []byte("llo")))    // 1
fmt.Println(bytes.HasPrefix(s, []byte("llo"))) // false
fmt.Println(bytes.HasSuffix(s, []byte("世界")))  // true

在源码中,Contains[Any/Rune]是通过Index[Any/Rune]来实现的,例如:

func ContainsAny(b []byte, chars string) bool {
    return IndexAny(b, chars) >= 0
}

HasPrefixHasSuffix是通过Equal来实现的,例如:

func HasPrefix(s, prefix []byte) bool {
    return len(s) >= len(prefix) && Equal(s[0:len(prefix)], prefix)
}

###转换

和转换相关的方法有:

  • func Title(s []byte) []byte
  • func ToLower(s []byte) []byte
  • func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte
  • func ToTitle(s []byte) []byte
  • func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte
  • func ToUpper(s []byte) []byte
  • func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte

例如:

s := []byte("heLLo 世界")
fmt.Println(string(bytes.Title(s)))   // HeLLo 世界
fmt.Println(string(bytes.ToLower(s))) // hello 世界
fmt.Println(string(bytes.ToTitle(s))) // HELLO 世界
fmt.Println(string(bytes.ToUpper(s))) // HELLO 世界

trim

和trim相关的方法有:

  • func Trim(s []byte, cutset string) []byte
  • func TrimFunc(s []byte, f func(r rune) bool) []byte
  • func TrimLeft(s []byte, cutset string) []byte
  • func TrimLeftFunc(s []byte, f func(r rune) bool) []byte
  • func TrimPrefix(s, prefix []byte) []byte
  • func TrimRight(s []byte, cutset string) []byte
  • func TrimRightFunc(s []byte, f func(r rune) bool) []byte
  • func TrimSpace(s []byte) []byte
  • func TrimSuffix(s, suffix []byte) []byte

例如:

s := []byte("hello olleh")
fmt.Println(string(bytes.TrimLeft(s, "hel")))            // o olleh
fmt.Println(string(bytes.TrimRight(s, "hel")))           // hello o
fmt.Println(string(bytes.Trim(s, "hel")))                // o o
fmt.Println(string(bytes.TrimPrefix(s, []byte("hel"))))  // lo olleh
fmt.Println(string(bytes.TrimSuffix(s, []byte("lleh")))) // hello o

其中最基本的两个方法是TrimLeftFuncTrimRightFuncTrimLeftTrimRightTrimFunc都是基于这两个方法。例如:

func TrimFunc(s []byte, f func(r rune) bool) []byte {
    return TrimRightFunc(TrimLeftFunc(s, f), f)
}

TrimTrimSpace都是基于TrimFunc方法。

TrimPrefixTrimSuffix其实都是简单使用了切片操作。

split 和 join

相关方法有:

  • func Split(s, sep []byte) [][]byte
  • func SplitAfter(s, sep []byte) [][]byte
  • func SplitAfterN(s, sep []byte, n int) [][]byte
  • func SplitN(s, sep []byte, n int) [][]byte
  • func Fields(s []byte) [][]byte
  • func FieldsFunc(s []byte, f func(rune) bool) [][]byte
  • func Join(s [][]byte, sep []byte) []byte

例如:

s := []byte("hello,world,welcome")

arr := bytes.Split(s, []byte(","))
for _, a := range arr {
    fmt.Print(string(a), " ")
}
// hello world welcome

arr = bytes.SplitAfter(s, []byte(","))
for _, a := range arr {
    fmt.Print(string(a), " ")
}
// hello, world, welcome

SplitAfter相比于Split,会包含分隔符。

SplitNSplitAfterNSplitSplitAfter相似,只不过限制了最大的切分个数,超过部分不再切分。例如:

s := []byte("hello,world,welcome")

arr := bytes.SplitN(s, []byte(","), 2)
for _, a := range arr {
    fmt.Print(string(a), " ")
}
// hello world,welcome

Fields是通过连续的空字符来切分,例如:

s := []byte("  hello  world   welcome ")
arr := bytes.Fields(s)
for _, a := range arr {
    fmt.Print(string(a), " ")
}
// hello world welcome

FieldsFunc则是通过一个函数来检测切分条件,实际上,Fields是调用了FieldsFunc

func Fields(s []byte) [][]byte {
    return FieldsFunc(s, unicode.IsSpace)
}

Join用于连接操作,例如:

s := [][]byte{
    []byte("hello"),
    []byte("world"),
    []byte("welcome"),
}
fmt.Println(string(bytes.Join(s, []byte(", "))))
// hello, world, welcome

其它操作

  • func Map(mapping func(r rune) rune, s []byte) []byte
  • func Repeat(b []byte, count int) []byte
  • func Replace(s, old, new []byte, n int) []byte
  • func Runes(s []byte) []rune

例如:

s := []byte("hello")
fmt.Println(string(bytes.Repeat(s, 3)))                             // hellohellohello
fmt.Println(string(bytes.Replace(s, []byte("l"), []byte("L"), 1)))  // heLlo
fmt.Println(string(bytes.Replace(s, []byte("l"), []byte("L"), -1))) // heLLo

s = []byte("hello 世界")
fmt.Println(s)              // [104 101 108 108 111 32 228 184 150 231 149 140]
fmt.Println(bytes.Runes(s)) // [104 101 108 108 111 32 19990 30028]

f := func(r rune) rune { return r + 1 }
fmt.Println(string(bytes.Map(f, []byte("abcdefg")))) // bcdefgh

Buffer

Buffer定义了一个缓冲区,其定义如下:

type Buffer struct {
    buf       []byte            // contents are the bytes buf[off : len(buf)]
    off       int               // read at &buf[off], write at &buf[len(buf)]
    runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune
    bootstrap [64]byte          // memory to hold first slice; helps small buffers avoid allocation.
    lastRead  readOp            // last read operation, so that Unread* can work correctly.
}

它有一个内在的buf用于存储缓冲数据,off表示缓冲区起始位置。因此实际的数据位于offlen(buf)之间。执行Read操作的时候,会修改off的值;执行Write操作的时候,会改变buf的长度。

可以通过如下方式创建新的Buffer

var a bytes.Buffer
b := bytes.NewBuffer([]byte("hello"))
c := bytes.NewBufferString("hello")

基本操作

Buffer的基本操作有:

  • func (b *Buffer) Len() int
  • func (b *Buffer) Cap() int
  • func (b *Buffer) Bytes() []byte
  • func (b *Buffer) String() string

例如:

buf := bytes.NewBufferString("hello")
buf.ReadByte()
fmt.Println(buf.Len())    // 4
fmt.Println(buf.Cap())    // 8
fmt.Println(buf.Bytes())  // [101 108 108 111]
fmt.Println(buf.String()) // ello

Truncate 和 Grow

Truncate可以截短缓冲区:

func (b *Buffer) Truncate(n int) {
    b.lastRead = opInvalid
    switch {
    case n < 0 || n > b.Len():
        panic("bytes.Buffer: truncation out of range")
    case n == 0:
        // Reuse buffer space.
        b.off = 0
    }
    // 截取前n个缓冲数据,如果n为0,则相当于buf重置
    b.buf = b.buf[0 : b.off+n]
}

例如:

buf := bytes.NewBufferString("hello")
buf.Truncate(3)
fmt.Println(buf) // hel
buf.Truncate(0)
fmt.Println(buf.Len()) // 0

Reset方法其实就是执行了Truncate(0)

Grow可以扩展缓冲区从而确保可以容纳更多缓冲数据:

func (b *Buffer) Grow(n int) {
    if n < 0 {
        panic("bytes.Buffer.Grow: negative count")
    }
    m := b.grow(n)
    // grow操作会在缓冲数据区之后增加一片空白区域
    // m表示的是数据区的末尾位置
    // 因此这里需要通过切片操作保证Len操作的正确性
    b.buf = b.buf[0:m]
}

func (b *Buffer) grow(n int) int {
    m := b.Len()
    // 如果缓冲区为空,则重置
    if m == 0 && b.off != 0 {
        b.Truncate(0)
    }
    // 超出缓冲区容量
    if len(b.buf)+n > cap(b.buf) {
        var buf []byte
        // 初始化缓冲区
        if b.buf == nil && n <= len(b.bootstrap) {
            buf = b.bootstrap[0:]
        } 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.
            // m为当前缓冲区的数据量,n为扩展大小,或者说即将写入的数据量
            // 因此m+n可以理解为新的缓冲数据量
            // 如果缓冲数据量不超过一半容量,则不需要新分配内存
            copy(b.buf[:], b.buf[b.off:])
            buf = b.buf[:m]
        } else {
            // 如果缓冲数据量超过一半容量,则需要新分配内存
            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
}

read

Read操作从缓冲区中读取数据:

func (b *Buffer) Read(p []byte) (n int, err error) {
    b.lastRead = opInvalid
    // 缓冲区为空,重置
    if b.off >= len(b.buf) {
        b.Truncate(0)
        if len(p) == 0 {
            return
        }
        return 0, io.EOF
    }
    // 将数据从缓冲区中拷贝出来,并更新off的值
    n = copy(p, b.buf[b.off:])
    b.off += n
    if n > 0 {
        b.lastRead = opRead
    }
    return
}

例如:

buf := bytes.NewBufferString("hello world")
p := make([]byte, 3)
buf.Read(p)
fmt.Println(string(p)) // hel

Next方法与Read基本类似,只不过参数不是一个slice而是一个数值表示要读取的数据量,另外一个区别是:Read操作是从缓冲区拷贝数据到新的slice,而Next是对当前缓冲区直接进行slice操作并返回结果。

func (b *Buffer) Next(n int) []byte {
    b.lastRead = opInvalid
    m := b.Len()
    if n > m {
        n = m
    }
    // 对当前缓冲区直接进行slice操作
    data := b.buf[b.off : b.off+n]
    b.off += n
    if n > 0 {
        b.lastRead = opRead
    }
    return data
}

其它与read相关的方法有:

  • func (b *Buffer) ReadByte() (byte, error)
  • func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
  • func (b *Buffer) ReadRune() (r rune, size int, err error)
  • func (b *Buffer) ReadString(delim byte) (line string, err error)

例如:

buf := bytes.NewBufferString("hello,世界!")

c, _ := buf.ReadByte()
fmt.Println(string(c)) // h

s, _ := buf.ReadBytes(',')
fmt.Println(string(s)) // ello,

r, _, _ := buf.ReadRune()
fmt.Println(string(r)) // 世

l, _ := buf.ReadString('!')
fmt.Println(l) // 界!

write

Write用于向缓冲区中写入数据:

func (b *Buffer) Write(p []byte) (n int, err error) {
    b.lastRead = opInvalid
    // 首先通过grow操作确保缓冲区可以容纳更多的数据
    m := b.grow(len(p))
    // 将数据拷贝到缓冲区中
    return copy(b.buf[m:], p), nil
}

其相关的方法有:

  • func (b *Buffer) Write(p []byte) (n int, err error)
  • func (b *Buffer) WriteByte(c byte) error
  • func (b *Buffer) WriteRune(r rune) (n int, err error)
  • func (b *Buffer) WriteString(s string) (n int, err error)

例如:

var buf bytes.Buffer

buf.Write([]byte("hello"))
fmt.Println(buf.String()) // hello

buf.WriteByte(',')
fmt.Println(buf.String()) // hello,

buf.WriteRune('世')
fmt.Println(buf.String()) // hello,世

buf.WriteString("界!")
fmt.Println(buf.String()) // hello,世界!

unread

unread操作会将已经读取的数据重新归入到缓冲区,本质上就是减小off的值。相关的方法有:

  • func (b *Buffer) UnreadByte() error
  • func (b *Buffer) UnreadRune() error
func (b *Buffer) UnreadByte() error {
    // 只有当上一次的操作是读操作的时候才可以执行unread操作
    if b.lastRead != opReadRune && b.lastRead != opRead {
        return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
    }
    b.lastRead = opInvalid
    if b.off > 0 {
        b.off--
    }
    return nil
}

例如:

buf := bytes.NewBufferString("hello")

buf.Read(make([]byte, 3))
fmt.Println(buf) // lo

err := buf.UnreadByte()
if err != nil {
    fmt.Println(err)
} else {
    fmt.Println(buf) // llo
}

buf.WriteByte('a')
err = buf.UnreadByte()
if err != nil {
    fmt.Println(err) // bytes.Buffer: UnreadByte: previous operation was not a read
} else {
    fmt.Println(buf)
}

ReadFrom 和 WriteTo

  • func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)
  • func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)

ReadFrom从一个reader中读取数据到缓冲区,WriteTo将缓冲区中的数据写入到一个writer中。例如:

r := bytes.NewReader([]byte("hello world"))
buf := new(bytes.Buffer)

buf.ReadFrom(r)
buf.WriteTo(os.Stdout)

Reader

bytes.Reader可以将一个[]byte类型作为reader来使用,通过NewReader方法可以创建一个reader,例如:

r := bytes.NewReader([]byte("hello world"))
b := make([]byte, 5)
r.Read(b)
fmt.Println(string(b)) // hello

其定义如下:

type Reader struct {
    s        []byte
    i        int64 // current reading index
    prevRune int   // index of previous rune; or < 0
}

其中s存放着数据,i表示当前读取到的下标,prevRune记录着之前读取的一个rune的下标,用于UnreadRune操作。

基本操作

  • func (r *Reader) Len() int
  • func (r *Reader) Size() int64
  • func (r *Reader) Reset(b []byte)

Len返回的是未读取的数据长度,Size返回的是总的数据长度,Reset重置了数据区。例如:

r := bytes.NewReader([]byte("hello world"))
r.ReadByte()
fmt.Println(r.Len())  // 10
fmt.Println(r.Size()) // 11
r.Reset([]byte("welcome"))
fmt.Println(r.Len()) // 7

这几个方法的源码比较简单,不做赘述。

read

和read相关的方法有:

  • 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)
  • func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)

它们本质上都是讲数据从reader.s拷贝出来,然后更新reader.i的值。其中ReadAt是从特定位置读取数据,例如:

r := bytes.NewReader([]byte("hello world"))
b := make([]byte, 5)
r.ReadAt(b, 6)
fmt.Println(string(b)) // world

unread

有两个方法:

  • func (r *Reader) UnreadByte() error
  • func (r *Reader) UnreadRune() error

其中UnreadByte只有在数据已经读取了之后才有效,UnreadRune只有在ReadRune之后才有效。源码比较简单,不做赘述。

Seek

Seek方法本质上是改变了reader.i的值。例如:

r := bytes.NewReader([]byte("hello world"))

r.Seek(4, io.SeekStart)
b, _ := r.ReadByte()
fmt.Println(string(b)) // o

r.Seek(3, io.SeekCurrent)
b, _ = r.ReadByte()
fmt.Println(string(b)) // r

r.Seek(-4, io.SeekEnd)
b, _ = r.ReadByte()
fmt.Println(string(b)) // o
}

WriteTo

WriteTo可以将数据写入到一个writer中,例如:

r := bytes.NewReader([]byte("hello world"))
r.WriteTo(os.Stdout)

标签:fmt,bytes,Println,func,go,byte,buf
From: https://www.cnblogs.com/codestack/p/17984386

相关文章

  • go 库I/O
    之前也有博客记录之goio包bufio#Readerbufio.Reader对io.Reader进行了包装,提供了缓冲区功能。定义如下:typeReaderstruct{buf[]byterdio.Reader//readerprovidedbytheclientr,wint//bufreadandwriteposi......
  • 1.27号(本周六)直播:golang开发远程控制工具
    本次的课程的内容为:1、远控编写2、工具代码编写3、工具测试 1月27日晚20:00,我们不见不散~ Ms08067安全实验室专注于网络安全知识的普及和培训,是专业的“图书出版+培训”的网络安全在线教育平台,专注于网络安全领域中高端人才培养。平台已开设Web安全零基础就业,Web高级安全......
  • 2024-01-24:用go语言,已知一个n*n的01矩阵, 只能通过通过行交换、或者列交换的方式调整矩
    2024-01-24:用go语言,已知一个n*n的01矩阵,只能通过通过行交换、或者列交换的方式调整矩阵,判断这个矩阵的对角线是否能全为1,如果能返回true,不能返回false。我们升级一下:已知一个n*n的01矩阵,只能通过通过行交换、或者列交换的方式调整矩阵,判断这个矩阵的对角线是否能全为1,如果......
  • Golang map实现分析
    数据结构go的map采用数组+链表形式存储,数据存放于hmap中:typehmapstruct{countint//哈希表的元素个数,即len()flagsuint8//map状态Buint8//2^B为桶的数量noverflowuint16//溢出桶的数量(预估)hash0uint32//hashs......
  • Go Modules
    GoModules于1.11发布,自1.14之后推荐在生产中使用,其替代了传统的GOPATH模式,作为go的依赖管理工具。认识GOPATHGOPATH目录下一共包含了三个子目录,分别是:bin:存储所编译生成的二进制文件pkg:存储预编译的目标文件,以加快程序的后续编译速度src:存储所有.go文件或源代码。在编写Go......
  • 单实例mongodb 部署
    配置文件mkdir/data/mongopush/{log,data,conf,scripts,tmp}systemLog:destination:filelogAppend:truelogRotate:reopenpath:/data/mongopush/log/mongodb.logstorage:dbPath:/data/mongopush/datajournal:enabled:truedirectoryPerDB:tru......
  • Go-命令行参数解析
    1.解析命令行参数程序在执行时,获取在命令行启动程序是使用的参数命令行(Commandlineinterface--CLI):基于文本来查看、处理、操作计算机的界面,又被称为终端、控制台命令:在命令行执行的程序,一般是一行,包含命令名字、子命令与命令相关的选项(Flag),Flag:传递给命令的参数......
  • 从 fatal 错误到 sync.Map:Go中 Map 的并发策略
    从fatal错误到sync.Map:Go中Map的并发策略原创 波罗学 码途漫漫 2024-01-2121:00 发表于上海 听全文为什么Go语言在多个goroutine同时访问和修改同一个map时,会报出fatal错误而不是panic?我们该如何应对map的数据竞争问题呢?码途漫漫踏实地写......
  • arcengine GP调用PolygonToLine 报错 -2147467259
    这个原因是传参数问题;GP调用面转线工具时,不能利用该方式传入参数IGpValueTableObjectgpValueTableObject=newGpValueTableObject();//对一个及以上要素类进行相交运算gpValueTableObject.SetColumns(2);objecto1=pFeatureClass2;//输入IFeatureC......
  • GORM高级查询
    GORM高级查询准备数据typeStudentstruct{IDuint`gorm:"size:3"`Namestring`gorm:"size:8"`Ageint`gorm:"size:3"`GenderboolEmail*string`gorm:"size:32"`}func(stuStudent)TableName()s......