• 【Go语言】I/O专题


    说明:这个专题,包含了Go语言中关于I/O操作涉及的包、方法、类型的全讲

    1.bytes包:字节切片、Buffer和Reader

    学习本部分之前,希望对Go语言新特性--切片有所了解。

    Go语言标准库bytes包,提供了对字节切片进行读写操作的一系列函数和方法,主要包括三部分:1.数组切片([]byte)处理函数2.Buffer对象3.Reader对象。

    1_1.字节切片处理函数

    Go语言提供的字节切片处理函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。

    1_1_1.字节切片基本处理函数

    字节切片的基本处理函数主要有Contains(),Count(),Map(),Repeat(),Replace(),Rune()和Join()共七个函数,下面分别介绍。

    (1)Contains()函数。Contains()函数的功能室检查字节切片b是否包含子切片subslice,如果包含返回true,否则返回false。该函数原型定义如下:

    	func Contains(b, subslice []byte) bool

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("Golang")
        subslice1 := []byte("go")
        subslice2 := []byte("Go")
        fmt.Println(bytes.Contains(s, subslice1))
        fmt.Println(bytes.Contains(s, subslice2))
    }

    该例测试结果为:

    false
    true

    (2)Count()函数。Count()函数的功能室计算子字节切片sep在字节切片s中非重叠示例的数量,该函数原型的定义如下:

    	func Count(s, sep []byte) int 

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("banana")
        sep1 := []byte("ban")
        sep2 := []byte("na")
        sep3 := []byte("a")
        fmt.Println(bytes.Count(s, sep1))
        fmt.Println(bytes.Count(s, sep2))
        fmt.Println(bytes.Count(s, sep3    ))
    }

    该例测试结果是:

    1
    2
    3

    (3)Map()函数。Map()函数的功能是:首先把s转换为UTF-8编码的字节序列,然后使用mapping函数把s中的每个Unicode字符映射成对应的字符,最后将映射结果存放到一个新创建的字节切片,并返回此新字节切片。该函数原型定义如下:

    	func Map(mapping func(r rune) rune, s []byte) []byte 

    在函数Map()中参数mapping映射函数;参数s是被处理的字节切片。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("同学们,上午好!")
        m := func(r rune) rune {
            if r == '上' {
                r = '下'
            }
            return r
        }
        fmt.Println(string(s))
        fmt.Println(string(bytes.Map(m, s)))
    }

    该例的测试结果是:

    同学们,上午好!
    同学们,下午好!

    (4)Repeat()函数。Repeat()函数的功能是把切片b复制count此组合成一个新的字节切片并返回。该函数原型定义如下:

    func Repeat(b []byte, count int) []byte

    在函数Repeat()中,参数b是被复制的字节切片;参数count是复制次数。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("na")
        count := 2
        fmt.Println("ba" + string(bytes.Repeat(b, count)))
    }

    该例测试结果是:

    banana

    Replace()函数。Replace()函数的功能是返回字节切片s的一个副本,并把前n个不重叠的子切片old替换为new;如果n<0则不限制替换的数量。该函数原型定义如下:

    	func Replace(s, old, new []byte, n int) []byte 

    在函数Replace()中,参数s是原字节切片;参数old是被替换的子切片;参数new是替换切片;参数n是替换次数。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("google")
        old := []byte("o")
        news := []byte("oo")
        n := 1
        fmt.Println(string(bytes.Replace(s, old, news, n)))
        fmt.Println(string(bytes.Replace(s, old, news, -1)))
    }

    该例测试结果为:

    gooogle
    goooogle

    (6)Rune()函数。Rune()函数的功能是把s转换为UTF-8编码的字节序列,并返回对应的Unicode切片。该函数原型定义如下:

    	func Runes(s []byte) []rune 

    在函数Rune()中,参数s是需要被转换的字节切片。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("中华人名共和国")
        r := bytes.Runes(s)
        fmt.Printf("转换前字符串 %q长度: %d字节
    ", string(s), len(s))
        fmt.Printf("转换后字符串 %q长度: %d字节
    ", string(r), len(r))
    }

    该例的测试结果为:

    转换前字符串 "中华人名共和国"长度: 21字节
    转换后字符串 "中华人名共和国"长度: 7字节

    (7)Join()函数。Join()函数的功能是用字节切片sep把a中的每个字节切片连成一个字节切片并返回。该函数的原型定义如下:

    	func Join(s [][]byte, sep []byte) []byte 

    在函数Join()中,参数s是字节切片的切片;参数sep是用于连接的字节切片。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := [][]byte{[]byte("你好"), []byte("世界")}
        sep := []byte(",")
        fmt.Println(string(bytes.Join(s, sep)))
    }

    该例的测试结果是:

    你好,世界
    
    
    

    1_1_2.字节切片比较函数

    字节切片比较函数共有三个:Compare()、Equal()、EqualFold(),它们的作用和返回值都有所区别下面分别介绍。

    (1)Compare()函数。Compare()函数的功能室根据字节的值比较字节切片a和b的大小。如果a=b,返回0,如果a>b,返回1,如果a< b返回-1.该函数原型定义如下:

    	func Compare(a, b []byte) int 

    在函数Compare()中,参数a b是需要比较两个字符切片。

    (2)Equal()函数。Equal()函数的功能是比较两个字节切片是否相等,如果参数为nil,则等同于空的字节切片。如果a=b,则返回true;否则,返回false。该函数的定义如下:

    	func Equal(a, b []byte) bool 

    在函数Equal()中,参数a b是需要比较的连个字节切片。

    (3)EqualFold()函数。EqualFold()函数的功能是把s和t转换成UTF-8字符串进行比较,并且忽略大小写。如果s=t,返回true;否则,返回false。该函数原型定义如下:

    	func EqualFold(s, t []byte) bool 

    在函数EqualFold()中,参数s t是需要比较的两个字节切片。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        a := []byte("abc")
        b := []byte("Abc")
        s := []byte("GOLANG")
        t := []byte("golang")
        fmt.Println(bytes.Compare(a, b))
        fmt.Println(bytes.Equal(a, b))
        fmt.Println(bytes.EqualFold(s, t))
    }

    该例测试结果为:

    1
    false
    true
    
    
    

    1_1_3.字节切片前后缀检查函数

    HasPrefix()函数和HasSuffix()函数可以检查字节切片的前后缀,并返回一个部卫星的检查结果。

    (1)HasPrefix()函数。HasPrefix()函数的功能是检查字节切片s的前缀是否为prefix。如果是,则返回true,如果不是返回false。该函数的原型定义如下:

    	func HasPrefix(s, prefix []byte) bool 

    在函数HashPrefix中,参数s是需要检查的字节切片;参数prefix是前缀切片。

    (2)HashSuffix()函数。功能是检查字节切片s的后缀是否为suffix,如果是返回true。函数原型定义如下:

    	func HasSuffix(s, suffix []byte) bool 

    在函数HasSuffix中,参数s是需要检查的字节切片;参数suffix是后缀切片。

    例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("recover")
        prefix := []byte("re")
        suffix := []byte("ed")
        fmt.Println(bytes.HasPrefix(s, prefix))
        fmt.Println(bytes.HasSuffix(s, suffix))
    }

    结果:

    true
    false
    
    
    

    1_1_4.字节切片位置索引函数

    字节切片位置索引函数共有8个:Index()、IndexAny()、IndexByte()、IndexFunc()、IndexRune()、LastIndex()、LastIndexAny()和LastIndexFunc().函数原型如下:

    	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 LastIndexFunc(s []byte, f func(r rune) bool) int 

    (1)Index()函数功能是返回sep在s中第一次出现的位置索引(从0开始),如果sep中不在s中返回-1.

    (2)IndexAny()函数的功能是把s结实为UTF-8编码的字节序列,返回chars中任何一个字符在s中第一次出现的位置索引;如果s中不包含chars中任何一个字符返回-1

    (3)IndexByte()函数的功能是检查字节c在s中第一次出现的位置索引;如果s中不包含c则返回-1

    (4)IndexFunc()函数的功能是把s解释成UTF-8字节序列,并返回第一个满足f(c)=true的字符c的位置索引。如果没有满足的则返回-1

    (5)IndexRune()函数的功能是把s解释成UTF-8字节序列,并返回rune类型的字符r在s中的位置索引;如果s中不包含r则返回-1

    (6)LastIIndex()函数的功能是返回sep在s中最后一次出现的位置索引,如果s中不包含sep则返回-1

    (7)LastIndexAny()函数的功能是把s解释成UTF-8字节序列,返回chars中任一字符在s中最后出现的位置索引。如果chars为空或者s中不包含chars中的任意字符,则返回-1.

    (8)LastIndexFunc()函数的功能是把s解释成UTF-8字节序列,返回满足f(s)=true的字符c在s中最后一次出现位置的索引。如果没找到 返回-1

    示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("Google")
        sep := []byte("o")
        chars := "gle"
        var c byte = 'g'
        var r rune = 'l'
        fmt.Printf("切片%q在%q中的位置索引是: %d
    ", sep, s, bytes.Index(s, sep))
        fmt.Printf("切片%q的任一字符在%q中的位置索引是: %d
    ", chars, s, bytes.IndexAny(s, chars))
        fmt.Printf("byte型字符%q在%q中的位置索引是: %d
    ", c, s, bytes.IndexByte(s, c))
        fmt.Printf("切片%q中第一个符合f()字符索引是: %d
    ", s, bytes.IndexFunc(s, f))
        fmt.Printf("rune型字符%q在%q中的位置索引是: %d
    ", r, s, bytes.IndexRune(s, r))
    
        fmt.Printf("切片%q在%q中最后的位置索引是: %d
    ", sep, s, bytes.LastIndex(s, sep))
        fmt.Printf("切片%q的任一字符在%q中最后的位置索引是:%d
    ", chars, s, bytes.LastIndexAny(s, chars))
        fmt.Printf("切片%q中最后一个符合f()字符索引是: %d
    ", s, bytes.LastIndexFunc(s, f))
    }
    func f(a rune) bool {
        if a > 'k' {
            return true
        } else {
            return false
        }
    }

    该例的测试结果为:

    切片"o"在"Google"中的位置索引是: 1
    切片"gle"的任一字符在"Google"中的位置索引是: 3
    byte型字符'g'在"Google"中的位置索引是: 3
    切片"Google"中第一个符合f()字符索引是: 1
    rune型字符'l'在"Google"中的位置索引是: 4
    切片"o"在"Google"中最后的位置索引是: 2
    切片"gle"的任一字符在"Google"中最后的位置索引是:5
    切片"Google"中最后一个符合f()字符索引是: 4
    
    
    

    1_1_5.字节切片分割函数

    字节切片分割函数共有6个:Fields()、FieldsFunnc()、Split()、SplitN()、SplitAfter()和SplitAfterN().函数原型如下:

    	func Fields(s []byte) [][]byte wq
    	func FieldsFunc(s []byte, f func(rune) bool) [][]byte 
    	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 

    Fields()函数的功能是把字节切片s按照一个或者连续多个空白字符分割成多个字节切片,如果s只包含空白字符则返回空字节切片。其中参数s准备分割的字节切片。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("I'm a student.")
        for _, f := range bytes.Fields(s) {
            fmt.Printf("%q", f)
        }
    }

    测试结果为:

    "I'm""a""student."

    FieldsFunc()函数功能是把s解释为UTF-8编码的字符序列,对于每个Unicode字符c,如果f(c)返回true就把c作为分割字符对s进行拆分。如果所有字符都满足f(c)为true,则返回空的切片。示例:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("小明和爸爸和妈妈")
        for _, f := range bytes.FieldsFunc(s, f) {
            fmt.Printf("%q", f)
        }    
    }
    func f(a rune)bool{
        if a=='和'{
            return true
        }else{
            return false
        }
    }

    测试结果为:

    "小明""爸爸""妈妈"

    Split()函数的功能是把s用sep分割成多个字节切片并返回。如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符。Split()等效于参数为n的SplitN()函数。示例:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("Hello,world")
        sep := []byte(",")
        for _, f := range bytes.Split(s, sep) {
            fmt.Printf("%q", f)
        }
    }

    测试结果为:

    "Hello""world"

    SplitAfter()函数的功能是把s用sep分割成多个字节切片并返回。如果sep为空,Split则把s切分成每个字节切片对应一个UTF-8字符。参数n决定返回长度,n>0,最多返回n个子切片;n==0返回s n< 0返回所有子切片。示例:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("南瓜,黄瓜,西红柿,茄子")
        sep := []byte(",")
        n := 2
        for _, f := range bytes.SplitN(s, sep, n) {
            fmt.Printf("%q
    ", f)
        }
        for _, f := range bytes.SplitN(s, sep, 0) {
            fmt.Printf("%q
    ", f)
        }
        for _, f := range bytes.SplitN(s, sep, -1) {
            fmt.Printf("%q", f)
        }
    }

    测试结果为:

    "南瓜"
    "黄瓜,西红柿,茄子"
    "南瓜""黄瓜""西红柿""茄子"

    SplitAfter()函数功能使用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。示例:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("managerteacherworkerfarmerstudent")
        sep := []byte("er")
        for _, f := range bytes.SplitAfter(s, sep) {
            fmt.Printf("%q", f)
        }
    }

    测试结果为:

    "manager""teacher""worker""farmer""student"

    SplitN()函数功能是用sep作为后缀把s切分成多个字节切片并返回。如果sep为空,则把s切分成每个字节切片对应一个UTF-8字符。参数n决定返回切片的长度:如果n>0,最多返回n个子字节切片,子切片可能包含未切分的字节序列;如果n=0,返回空切片如果n< 0返回所有子切片。示例:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("managerteacherworkerfarmerstudent")
        sep := []byte("er")
        n := 3
        for _, f := range bytes.SplitAfterN(s, sep, n) {
            fmt.Printf("%q", f)
        }
        fmt.Println()
        for _, f := range bytes.SplitAfterN(s, sep, 0) {
            fmt.Printf("%q", f)
        }
        fmt.Println()
        for _, f := range bytes.SplitAfterN(s, sep, -1) {
            fmt.Printf("%q", f)
        }
    }

    测试结果为:

    "manager""teacher""workerfarmerstudent"
    
    "manager""teacher""worker""farmer""student"
    
    
    

    1_1_6.字节切片大小写处理函数

    字节切片大小写处理函数共有7个:Title()、ToTitle()、ToTitleSpecial()、ToLower()、ToLowerSpecial()、ToUpper()和ToUpperSpecial().以下为函数原型:

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

    (1)Title()函数的功能是返回s的一个副本,把s中的每个单词的首字母改为Unicode字符的大写。

    (2)ToTitle()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为大写。

    (3)ToTitleSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成大写。

    package main
    
    import (
        "bytes"
        "fmt"
        "unicode"
    )
    
    func main() {
        s := []byte("hello,world!")
        fmt.Println(string(bytes.Title(s)))
        fmt.Println(string(bytes.ToTitle(s)))
        fmt.Println(string(bytes.ToTitleSpecial(unicode.AzeriCase, s)))
    }

    该例测试结果为:

    Hello,World!
    HELLO,WORLD!
    HELLO,WORLD!

    (4)ToLower()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为小写.

    (5)ToLowerSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成小写.

    package main
    
    import (
        "bytes"
        "fmt"
        "unicode"
    )
    
    func main() {
        s := []byte("Hello,World!")
        fmt.Println(string(bytes.ToLower(s)))
        fmt.Println(string(bytes.ToLowerSpecial(unicode.AzeriCase, s)))
    }

    该例测试结果为:

    hello,world!
    hello,world!

    (6)ToUpper()函数的功能是返回s的一个副本,并把其中的所有的Unicode字符转为大写。

    (7)ToUpperSpecial()函数功能是返回s的一个副本,并把其中所有Unicode字符都根据_case指定的规则转换成大写。

    package main
    
    import (
        "bytes"
        "fmt"
        "unicode"
    )
    
    func main() {
        s := []byte("hello,world!")
        fmt.Println(string(bytes.ToUpper(s)))
        fmt.Println(string(bytes.ToUpperSpecial(unicode.AzeriCase, s)))
    }

    该例测试结果为:

    HELLO,WORLD!
    HELLO,WORLD!
    
    
    

    1_1_7.子字节切片处理函数

    子字节切片处理函数共有9个:Trim()、TrimFunc()、TrimLeft()、TrimLeftFunc()、TrimRight()、TrimRightFunc()、TrimSpace()、TrimPrefix()和TrimSuffix()

    	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 TrimRight(s []byte, cutset string) []byte 
    	func TrimRightFunc(s []byte, f func(r rune) bool) []byte 
    	func TrimSpace(s []byte) []byte 
    	func TrimPrefix(s, prefix []byte) []byte
    	func TrimSuffix(s, suffix []byte) []byte 

    (1)Trim()函数的功能是返回s的子字节切片,cutset中任意出现在s的首部和尾部的连续字符将被删除。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        cutset := "hold!"
        fmt.Println(string(bytes.Trim(s, cutset)))
    }

    测试结果为:

    ello,wor

    (2)TrimFunc()函数功能是返回s的子字节切片,不包含s首部和尾部连接的满足f(c)=true的字符c。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        fmt.Println(string(bytes.TrimFunc(s, f)))
    }
    func f(a rune) bool {
        if a == 'h' || a == '!' {
            return true
        } else {
            return false
        }
    }

    测试结果为:

    ello,world

    (3)TrimLeft()函数的功能是返回s的子字节切片,cutset中任意出现在s首部的连续字符被删除。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        cutset := "hold"
        fmt.Println(string(bytes.TrimLeft(s, cutset)))
    }

    测试结果为:

    ello,world!

    (4)TrimLeftFunc()函数功能是返回s的一个子字节切片、不包含s首部连续满足f(c)=true的字符c。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        fmt.Println(string(bytes.TrimLeftFunc(s, f)))
    }
    func f(a rune) bool {
        if a == 'h' || a == '!' {
            return true
        } else {
            return false
        }
    }

    测试结果为:

    ello,world!

    (5)TrimRight()

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        cutset := "hold!"
        fmt.Println(string(bytes.TrimRight(s, cutset)))
    }

    测试结果为:

    hello,wor

    (6)TrimRightFunc()函数功能是返回s的一个子字节切片、不包含s尾部连续满足f(c)=true的字符c。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte("hello,world!")
        fmt.Println(string(bytes.TrimRightFunc(s, f)))
    }
    func f(a rune) bool {
        if a == 'h' || a == '!' {
            return true
        } else {
            return false
        }
    }

    测试结果为:

    hello,world

    (7)TrimSpace()函数功能是返回s的一个子字节切片,并删除s中开始和结尾处的连续的Unicode空白字符。例如:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := []byte(" hello,world! ")
        fmt.Println(string(bytes.TrimSpace(s)))
    }

    测试结果为:

    hello,world!

    (8)TrimPrefix()函数功能是返回s的一个子字节切片,并删除前缀为prefix的部分

    (9)TrimSuffix()函数功能是返回s的一个子字节切片,并删除后缀为suffix的部分

    1_2.Buffer

    在bytes包中,缓冲区(Buffer)是最常用的对字节切片进行I/O操作的对象。Buffer对象的定义如下:

    type Buffer struct {
            // contains filtered or unexported fields
    }

    默认情况下Buffer对象没有定义初始值,Buffer使用结构体自带的一个[64]byte数组作为存储空间。当超出限制时,另创建一个两倍的存储空间,并复制未读取的数据。当Buffer里的数据被完全读取后,会将写入位置重置到底层数据的开始处。因此只要读写操作平衡,就无须担心内存会持续增长。

    1_2_1.Buffer对象创建函数

    可以使用NewBuffer(buf []byte)和NewBufferString()函数创建Buffer对象,他们分别使用字节切片和字符串对Buffer进行初始化。

    (1)NewBuffer()函数。功能是创建一个Buffer,并用字节切片buf对它进行初始化。buf可以直接用来作为准备要读的数据;也可以用来指定写缓冲区的大小,这时要提前为buf分配内存空间,但是len(buf)为0.该函数的原型定义如下:

    	func NewBuffer(buf []byte) *Buffer

    (2)NewBufferString()函数。功能是创建一个Buffer,并用字符串s对它进行初始化。它通常用于读取已经存在的数据。该函数的原型定义如下:

    	func NewBufferString(s string) *Buffer

    1_2_2.Buffer写操作方法

    对Buffer对象的写操作方法共有5个函数:Write(),WriteByte(),WriteRune(),WriteString()和WriteTo()方法。原型定义如下:

    	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)
    	func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)

    (1)Write()方法.功能是把字节切片p写入Buffer中,该方法执行结束返回成功写入的字节数n和错误类型err。如果返回的n满足n==len(p),则err总是为nil,如果数据太大则Write会panic并产生ErrTooLarge异常。示例如下(参数p是要写入的切片):

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        p := []byte("Hello,world!")
        b := bytes.NewBuffer(nil)
        n, err := b.Write(p)
        fmt.Println(string(b.Bytes()), n, err)
    }

    测试结果为:

    Hello,world! 12 <nil>

    (2)WriteByte()方法。功能是写入一个字节,总是返回nil。这个返回值只是为了匹配bufio.Writer的Write函数。如果内部数据太大,WriteByte会panic并产生ErrTooLarge异常。示例如下(c是要写入的自己额数据,比如ASCII字符):

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        var c1, c2 byte = 'G', 'o'
        b := bytes.NewBuffer(nil)
        err := b.WriteByte(c1)
        b.WriteByte(c2)
        fmt.Println(string(b.Bytes()), err)
    }

    测试结果为:

    Go <nil>

    (3)WriteRune()方法。功能是把一个Unicode字符的UTF-8编码写入Buffer,并返回写入字节数n。err总是nil,这个返回类型是为了和bufio.Writer的WriteRune函数匹配。如果Buffer的缓冲区太大,则WriteRune会panic并产生ErrTooLarge异常。示例如下(参数r是要写入的rune类型的字符):

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        var r1, r2 rune = '中', '国'
        b := bytes.NewBuffer(nil)
        b.WriteRune(r1)
        b.WriteRune(r2)
        fmt.Println(string(b.Bytes()))
    }

    测试结果为:

    中国

    (4)WriteString()方法.功能是把s写入Buffer,返回值n为len(s),err总是为nil。如果内部缓冲区太大,WriteString会panic并产生ErrTooLarge异常。示例如下(参数s是要写入的字符串):

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        s := "你好,世界!"
        b := bytes.NewBuffer(nil)
        n, err := b.WriteString(s)
        fmt.Println(string(b.Bytes()), n, err)
    }

    测试结果为:

    你好,世界! 18 <nil>

    (5)WriteTo()方法。功能是把Buffer中的数据写入到I/O对象w中,直到数据为空或者遇到错误,返回值n总是足够用int表示,使用int64类型是为了和io.WriteTo接口匹配。任何写入时遇到的错误都会被返回。示例如下(参数w是要写入的I/O对象):

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang")
        b := bytes.NewBuffer(buf)
        w := bytes.NewBuffer(nil)
        n, err := b.WriteTo(w)
        fmt.Println(string(w.Bytes()), n, err)
    }

    测试结果为:

    Golang 6 <nil>

    1_2_3.Buffer读操作方法

    对Buffer的读操作方法共有6个:Read()、ReadByte()、ReadBytes()、ReadFrom()、ReadRune()和ReadString()方法,原型定义如下:

    	func (b *Buffer) Read(p []byte) (n int, err error)
    	func (b *Buffer) ReadByte() (c byte, err error)
    	func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
    	func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error)
    	func (b *Buffer) ReadRune() (r rune, size int, err error)
    	func (b *Buffer) ReadString(delim byte) (line string, err error)

    (1)Read()方法.功能是从Buffer中读取len(p)个字节,并复制到p中;如果Buffer中未读数据不足len(p),则把所有的数据都复制到p中。该方法执行完,返回实际读取的字节数n和错误类型err。如果Buffer中没有数据,则err为io.EOF(除非len(p)为0);否则err为nil。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Hello,world!")
        b := bytes.NewBuffer(buf)
        var p [8]byte
        n, err := b.Read(p[:])
        fmt.Println(string(p[:n]), n, err)
    }

    测试结果为:

    Hello,wo 8 <nil>

    (2)ReadByte()方法.功能是从Buffer中读取一个字节并返回,如果没有数据可读则err为io.EOF。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang")
        b := bytes.NewBuffer(buf)
        c, err := b.ReadByte()
        fmt.Println(string(c), err)
    }

    测试结果为:

    G <nil>

    (3)ReadBytes()方法.功能是从Buffer中读取数,直到第一次遇到分隔符"delim",把已读取的数据包括"delim"作为字节切片返回。如果在读取到"delim"前出现错误,则返回已经读取的数据和那个错误(通常是io.EOF).只有返回的数据不可以"delim"结尾时,ReadBytes才返回err非空。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Hello,world!")
        b := bytes.NewBuffer(buf)
        var delim byte = ','
        line, err := b.ReadBytes(delim)
        fmt.Println(string(line), err)
    }

    测试结果为:

    Hello, <nil>

    (4)ReadFrom()方法.功能是从I/O接口对象r中读取数据,并写入到Buffer中,直到r.Read返回io.EOF,除了io.EOF之外的错误会被ReadFrom返回。返回值n为以读取的字节数,err为r.Read返回的错误。如果读取的数据太大,ReadFrom会panic并产生ErrToolarge异常。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("中华人民共和国")
        r := bytes.NewBuffer(buf)
        b := bytes.NewBuffer(nil)
        n, err := b.ReadFrom(r)
        fmt.Println(string(b.Bytes()), n, err)
    }

    测试结果为:

    中华人民共和国 21 <nil>

    (5)ReadRune()方法.功能是从Buffer中读取一个unicode字符,同时返回它的UTF-8编码,如果没有数据可读则返回io.EOF。如果读取的不是UTF-8编码字节序列,则读取一个字节并返回U+FFFD.示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("中华人民共和国")
        b := bytes.NewBuffer(buf)
        r, size, err := b.ReadRune()
        fmt.Println(string(r), size, err)
    }

    测试结果为:

    中 3 <nil>

    (6)ReadString()方法.功能是读取数据指导遇到分隔符"delim",并把已读取的数据包含"delim"作为string返回。如果在遇到"delim"前出错,则把已读数据作为string和遇到的错误(通常是io.EOF)返回。当返回的string不以"delim"结尾时,才会返回非空err。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang is a beautiful language,I like it!")
        b := bytes.NewBuffer(buf)
        var delim byte = ','
        line, err := b.ReadString(delim)
        fmt.Println(line, err)
    }

    测试结果为:

    Golang is a beautiful language, <nil>

    1_2_4.Buffer其他操作方法

    对Buffer对象的其他操作方法共有8个:Byte()、Len()、Next()、Reset()、String()、Truncate()、UnreadByte()和UnreadRune(),函数原型:

    	func (b *Buffer) Bytes() []byte
    	func (b *Buffer) Len() int
    	func (b *Buffer) Next(n int) []byte
    	func (b *Buffer) Reset()
    	func (b *Buffer) String() string
    	func (b *Buffer) Truncate(n int)
    	func (b *Buffer) UnreadByte() error
    	func (b *Buffer) UnreadRune() error

    (1)Bytes()方法。功能是返回Buffer中未读取的字节数。它满足条件len(b.Bytes())=b.Len()。

    (2)Len()方法。功能是返回buffer中未读取数据的字节数。它满足条件b.Len()=len(b.Bytes()).示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang is a beautiful language,I like it!")
        b := bytes.NewBuffer(buf)
        var delim byte = ','
        fmt.Println("未执行读取操作前Buffer中数据和字节数")
        fmt.Println(string(b.Bytes()), b.Len())
        b.ReadString(delim)
        fmt.Println("执行读操作后Buffer中数据和字节数")
        fmt.Println(string(b.Bytes()), b.Len())
    }

    测试结果为:

    未执行读取操作前Buffer中数据和字节数
    Golang is a beautiful language,I like it! 41
    执行读操作后Buffer中数据和字节数
    I like it! 10

    (3)Next()方法。功能是返回Buffer中下n个未读取的字节没,本次读取会修改Buffer中的读取位置。如果Buffer中未读数据不足n字节,则返回全部未读数据。返回的字节切片在下次读或写前有效。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang")
        b := bytes.NewBuffer(buf)
        fmt.Println(string(b.Next(4)))
        fmt.Println(string(b.Next(4)))
    }

    测试结果为:

    Gola
    ng

    (4)Reset()方法。功能是把Buffer中的数据清空,等同于b.Truncate(0).

    (5)String()方法。功能是把Buffer中的未读取数据作为string返回。如果Buffer是个nil指针,则返回"<nil>"

    (6)Truncate()方法。功能是只保留前n个字节的数据并清除其余数据。当n<或者n>b.Len()时,则Truncate导致panic,当n=0时,等同于b.Reset()。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Hello,world!")
        b := bytes.NewBuffer(buf)
        fmt.Println("未执行Reset前Buffer中的内容:", string(b.Bytes()))
        b.Truncate(5)
        fmt.Println("执行Truncate后Buffer中内容:", string(b.Bytes()))
        b.Reset()
        fmt.Println("执行Reset后Buffer中内容:", string(b.Bytes()))
    }

    测试结果为:

    未执行Reset前Buffer中的内容: Hello,world!
    执行Truncate后Buffer中内容: Hello
    执行Reset后Buffer中内容:

    (7)UnreadByte()方法。功能是取消上次读取的最后一个字节,如果上次读取之后有过写操作,则返回错误。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("Golang")
        b := bytes.NewBuffer(buf)
        fmt.Println(string(b.Next(3)))
        b.UnreadByte()
        fmt.Println(string(b.Bytes()))
    }

    测试结果为:

    Gol
    lang

    (8)UnreadRune()方法。功能是取消上次ReadRune()读取的Unicode字符。如果最近一次写操作不是ReadRune,则返回一个错误。示例如下

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        buf := []byte("中华人民共和国")
        b := bytes.NewBuffer(buf)
        b.ReadRune()
        b.ReadRune()
        b.ReadRune()
        b.UnreadRune()
        fmt.Println(string(b.Bytes()))
    }

    测试结果为:

    人民共和国

    1_3.Reader

    Reader是另一个可以对字节切片进行操作的对象,与Buffer对象不同的是,Reader对象只是从字节切片中读取数据,不能写入数据,但是,Reader对象支持对字节切片进行定位操作。Reader对象定义如下:

    type Reader struct {
            // contains filtered or unexported fields
    }

    1_3_1.Reader对象创建函数

    Reader对象的创建函数式NewReader(),它的作用是创建一个Reader,数据为字节切片b,该函数原型定义如下:
    	func NewReader(b []byte) *Reader

    1_3_2.Reader对象操作方法

    Reader对象的操作方法共有8个:Len()、Read()、ReadAt()、ReadByte()、ReadRune()、Seek()、UnreadByte()和UnreadRune()。方法原型为:

    	func (r *Reader) Len() int
    	func (r *Reader) Read(b []byte) (n int, err error)
    	func (r *Reader) ReadAt(b []byte, off int64) (n int, err error)
    	func (r *Reader) ReadByte() (b byte, err error)
    	func (r *Reader) ReadRune() (ch rune, size int, err error)
    	func (r *Reader) Seek(offset int64, whence int) (int64, error)
    	func (r *Reader) UnreadByte() error
    	func (r *Reader) UnreadRune() error
    	func (r *Reader) WriteTo(w io.Writer) (n int64, err error)

    (1)Len()方法。功能是返回Reader中读取的字节数。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("Golang")
        r := bytes.NewReader(b)
        fmt.Println(r.Len())
    }

    测试结果为:

    6

    (2)Read()方法。功能是从Reader中读取Len(b)个字节,返回已读取的字节数。如果遇到错误则返回错误(通常是io.EOF)。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("Golang")
        var buf [3]byte
        r := bytes.NewReader(b)
        n, err := r.Read(buf[:])
        fmt.Println(string(buf[:n]), n, err)
        n, err = r.Read(buf[:])
        fmt.Println(string(buf[:n]), n, err)
        n, err = r.Read(buf[:])
        fmt.Println(string(buf[:n]), n, err)
    
    }

    测试结果为:

    Gol 3 <nil>
    ang 3 <nil>
     0 EOF

    (3)ReadAt()方法。功能是从Reader中偏移为off字节的为孩子读取len(b)个字节,并返回已读取得字节数;如果遇到错误则返回错误(通常是io.EOF)。ReadAt读取的数据不会从Reader中清除。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("Golang")
        var buf [3]byte
        r := bytes.NewReader(b)
        n, err := r.ReadAt(buf[:], 2)
        fmt.Println(string(buf[:n]), n, err)
        n, err = r.ReadAt(buf[:], 3)
        fmt.Println(string(buf[:n]), n, err)
        n, err = r.ReadAt(buf[:], 4)
        fmt.Println(string(buf[:n]), n, err)
    
    }

    测试结果为:

    lan 3 <nil>
    ang 3 <nil>
    ng 2 EOF

    (4)ReadByte()方法。功能是从Reader中读取一个字节并返回,如果遇到错误返回错误(通常是io.EOF)。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("Golang")
        r := bytes.NewReader(b)
        c, err := r.ReadByte()
        fmt.Println(string(c), err)
    }

    测试结果为:

    G <nil>

    (5)ReadRune()方法。功能是从Reader中按照UTF-8编码读取一个Unicode字符,返回此字符,其字符的UTF-8编码占用的字节数,如果遇到错误(通常是io.EOF)。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("中华人民共和国")
        r := bytes.NewReader(b)
        ch, size, err := r.ReadRune()
        fmt.Println(string(ch), size, err)
    }

    测试结果为:

    中 3 <nil>

    (6)Seek()方法。功能是实现了io.Seeker节后方法,用于设置下次读或写操作的位置,返回新的偏移位置字节数和错误(如果有).当whence=0,从起始位置计算offset,当whence=1,从当前位置计算offset,当whence=2从尾部位置计算offset。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("中华人民共和国")
        r := bytes.NewReader(b)
        r.Seek(3, 0) //从起始位置偏移3,应该是'华'字
        ch, size, err := r.ReadRune()
        fmt.Println(string(ch), size, err)
        r.Seek(3, 1) //从当前位置偏移3,应该是'民'字
        ch, size, err = r.ReadRune()
        fmt.Println(string(ch), size, err)
        r.Seek(-6, 2) //从尾部位置偏移3,应该是'和'字
        ch, size, err = r.ReadRune()
        fmt.Println(string(ch), size, err)
    }

    测试结果为:

    华 3 <nil>3 <nil>3 <nil>

    (7)UnreadByte()方法。功能是取消上次读取的最后一个字节,如果Buffer没有被读取过则UnreadByte也返回一个错误。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("Golang")
        var buf [6]byte
        r := bytes.NewReader(b) //Buffer还没被读取过,返回一个错误
        err := r.UnreadByte()
        fmt.Println(err)
        n, _ := r.Read(buf[:]) //第一次读取
        fmt.Println(string(buf[:n]), n)
        err = r.UnreadByte() //取消第一次读取的最后一个字节'g'
        fmt.Println(err)
        n, _ = r.Read(buf[:]) //第二次读取,Buffer中只剩'g'了
        fmt.Println(string(buf[:n]), n)
    }

    测试结果为:

    bytes.Reader: at beginning of slice
    Golang 6
    <nil>
    g 1

    (8)UnreadRune()方法。功能是取消上次ReadRune读取的Unicode字符。如果上次读取操作不是ReadRune,则返回错误。示例如下:

    package main
    
    import (
        "bytes"
        "fmt"
    )
    
    func main() {
        b := []byte("中华人民共和国")
        var buf [3]byte
        r := bytes.NewReader(b)
        r.Read(buf[:]) //用Read读取第一个Unicode字符'中'
        err := r.UnreadRune()
        fmt.Println(err)
        ch, _, _ := r.ReadRune() //用ReadRune读取第二个Unicode字符'华'
        fmt.Println(string(ch))
        err = r.UnreadRune() //取消上次读取的Unicode字符
        fmt.Println(err)
        ch, _, _ = r.ReadRune() //用ReadRune重新读取第二个Unicode字符'华'
        fmt.Println(string(ch))
    }

    测试结果为:

    bytes.Reader: previous operation was not ReadRune
    华
    <nil>

    2.io包

    在Java中按照对io流处理的基本单位可以分为这样几个模块(实际上JavaAPI的package组织形式也是按照这种分类方法)

    字节流(数据流中的最小单元为一个字节):InputStream和OutputStream是所有字节输入流、输出流的父类,二者都直接继承自java.lang.Object

    字符流(多用于读写文本文件。文本文件存放了用特定字符编码的字符):Reader和Writer是所有字符输入流、输出流的父类,二者都直接继承自java.lang.Object

    在Go语言中字节流和字符流处理的类型并没有被分隔,在bytes包中的三大部分:[]byte处理函数、Buffer和Reader都是对最基本的数据单位字节byte的处理,而这三部分不仅有字节处理函数还有字符处理函数,因为无论是字节流还是字符流最根本上还是对字节的操作。但是这三部分并没有明显的流的概念,只是简单地停留在字节数据操作的级别。

    Go语言真正定义流的概念是在io包中io包中包含了各种流类型的定义以及关闭和复制流等基本操作(不过非常有限),官方给出这样的说明Package io provides basic interfaces to I/O primitives意思是:io包提供了关于I/O基元的基本接口,可以理解为它主要是定义了I/O的容器(或者说是通道)

    而bufio包中详细定义了对流读写细节操作的方法,对I/O流的操作的各种方法基本上都在这里。其操作的对象也就是io包中定义的类型。

    3.bufio包

    Go语言标准库bufio包,实现了对数据I/O接口的缓冲功能。它封装与接口io.ReadWriter,io.Reader和io.Writer中,并对应创建对象ReadWriter、Reader或Writer,在提供缓冲的同时实现了一些文本基本I/O操作功能。

    3_1.ReadWriter对象

    ReadWriter对象可以对数据I/O接口io.ReadWriter进行输入输出缓冲操作,ReadWriter结构定义如下:
    type ReadWriter struct {
            *Reader
            *Writer
    }

    默认情况下,ReadWriter对象中存放了一对Reader和Writer指针,它同时提供了对数据I/O对象的读写缓冲功能。

    可以使用NewReadWriter()函数创建ReadWriter对象,该函数的功能是根据指定的Reader和Writer创建一个ReadWriter对象,ReadWriter对象将会向底层io.ReadWriter接口写入数据,或者从io.ReadWriter接口读取数据。该函数原型声明如下:

    	func NewReadWriter(r *Reader, w *Writer) *ReadWriter

    在函数NewReadWriter()中,参数r是要读取的来源Reader对象;参数w是要写入的目的Writer对象。

    3_2.Reader对象

    Reader对象可以对数据I/O接口io.Reader进行输入缓冲操作,Reader结构定义如下:

    type Reader struct {
            // contains filtered or unexported fields
    }

    默认情况下Reader对象没有定义初始值,输入缓冲区最小值为16.当超过限制时,另创建一个2倍的存储空间。

    3_2_1.Reader对象创建函数

    Reader对象的创建函数共有2个:NewReader()和NewReaderSize(),下面分别介绍:

    (1)NewReader()函数。功能是按照缓冲区默认长度创建Reader对象,Reader对象会从底层io.Reader接口读取尽量多的数据进行缓冲。该函数原型声明如下:

    	func NewReader(rd io.Reader) *Reader

    在函数NewReader()中,参数rd是io.Reader接口,Reader对象将从该接口读取数据.

    (2)和NewReaderSize()函数。功能是按照指定的缓冲区长度创建Reader对象,Reader对象会从底层io.Reader接口读取尽量多的数据进行缓存。该函数的原型声明如下:

    	func NewReaderSize(rd io.Reader, size int) *Reader

    在函数NewReaderSize()中,参数rd是io.Reader接口,参数size是指定的缓冲区字节长度。

    3_2_2.Reader对象操作方法

    Reader对象的操作方法共有12个:Read()、ReadByte()、ReadBytes()、ReadLine()、ReadRune()、ReadSlice()、ReadString()、UnreadByte()、UnreadRune()、Buffered()、Peek()、WriteTo()它们的原型声明如下:

    	
    	func (b *Reader) Read(p []byte) (n int, err error)
    	func (b *Reader) ReadByte() (c byte, err error)
    	func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    	func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
    	func (b *Reader) ReadRune() (r rune, size int, err error)
    	func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
    	func (b *Reader) ReadString(delim byte) (line string, err error)
    	func (b *Reader) UnreadByte() error
    	func (b *Reader) UnreadRune() error
    	func (b *Reader) Buffered() int
    	func (b *Reader) Peek(n int) ([]byte, error)
    	func (b *Reader) WriteTo(w io.Writer) (n int64, err error) 
    

    (1)Read()方法。功能是读取数据,并存放到字节切片p中。Read()执行结束会返回已读取的字节数,因为最多只调用底层的io.Reader一次,所以返回的n可能小于len(p);当字节流结束时,n为0,err为io.EOF。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("中华人民共和国")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        var buf [128]byte
        n, err := r.Read(buf[:])
        fmt.Println(string(buf[:n]), n, err)
    }

    测试结果为:

    中华人民共和国 21 <nil>

    (2)ReadByte()方法。功能是读取并返回一个字节。如果没有字节可读。则返回错误信息。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("Golang")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        c, err := r.ReadByte()
        fmt.Println(string(c), err)
    }

    测试结果为:

    G <nil>

    (3)ReadBytes()方法。功能是读取数据直到遇到第一个分隔符"delim",并返回读取的字节序列(包括"delim").如果在读到第一个"dleim"之前出错,它返回已读的数据和那个错误(通常是io.EOF)。只有当返回的数据不以"delim"结尾时,返回的err才不为空值。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("Hello,world!")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        var delim byte = ','
        line, err := r.ReadBytes(delim)
        fmt.Println(string(line), err)
    }

    测试结果为:

    Hello, <nil>

    (4)ReadLine()方法。功能是一个低级的用于读取一行数据的原语,大多数调用者应该使用ReadBytes(' ')或者ReadString(' ').ReadLine试图返回一行,不包括结尾的回车字符。如果一行太长了(超过缓冲区长度),canshu isPrefix会 设置为true并且只返回前面的数据,剩余的数据会在以后的调用中返回。当返回最后一行数据时,参数isPrefix会设置为false。返回的字节切片只在下一次调用ReadLine前有效。ReadLine或者返回一个非空的字节切片或者返回一个错误。但他们不会同时返回。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("Golang is a beautiful language.
     I like it!")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        line, prefix, err := r.ReadLine()
        fmt.Println(string(line), prefix, err)
    }

    测试结果为:

    Golang is a beautiful language. false <nil>

    (5)ReadRune()方法。功能是读取下一个UTF-8编码的字符,并返回Unicode编码和字节数。如果编码错误,ReadRune只读取一个字节并返回unicode.ReplacementChar(U+FFFD)和长度1.示例如下

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("中华人民共和国")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        ch, size, err := r.ReadRune()
        fmt.Println(string(ch), size, err)
    }

    测试结果为:

    中 3 <nil>

    (6)ReadSlice()方法。功能是读取数据直到分隔符"delim"处,并返回读取数据的字节切片,下次读取数据时返回的切片会失效。如果ReadSlice在查找到"delim"之前遇到错误,它返回读取的所有数据和那个错误(通常是io.EOF)。如果缓冲区满时也没有查找到delim,则返回ErrBufferFull错误。因为ReadSlice返回的数据会再下次I/O操作是被覆盖,大多调用者应该使用ReadBytes或者ReadString。只有当line不以"delim"结尾时,ReadSlice才会返回非空err。示例如下;

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("apple,banana,pear")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        var delim byte = ','
        line, err := r.ReadSlice(delim)
        fmt.Println(string(line), err)
        line, err = r.ReadSlice(delim)
        fmt.Println(string(line), err)
        line, err = r.ReadSlice(delim)
        fmt.Println(string(line), err)
    }

    测试结果为:

    apple, <nil>
    banana, <nil>
    pear EOF

    (7)ReadString()方法。功能是读取数据直到分隔符delim第一次出现,并返回一个包含delim的字符串。如果ReadString在读取到delim前遇到错误,它返回已读字符串和那个错误(通常是io.EOF)。只有当返回的字符串不以delim结尾时,ReadString才返回非空err。示例如下:

    <div class="cnblogs_code" style="background-color: #F5F5F5;border: 1px solid #CCCCCC;padding: 5px;"><pre>apple, &lt;nil&gt;<span style="color: #000000;">
    banana, </span>&lt;nil&gt;<span style="color: #000000;">
    pear EOF</span></pre></div>

    测试结果为:

    apple, <nil>

    (8)UnreadByte()方法。 功能是取消已读的最后一个字节(即把字节重新放回读取缓冲区的前部)。只有最近一次读取的单个字节才能取消读取

    (9)UnreadRune()方法。 功能是取消读取最后一次读取的unicode字符。如果最后一次读取操作不是ReadRune,会返回一个错误(在这方面它比UnreadByte更严格,因为UnreadByte会取消上次任意读操作的最后一个字节)。

    (10)Buffered()方法。功能是返回可从缓冲区读出数据的字节数。示例如下;

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("中华人民共和国")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        var buf [12]byte
        n, err := r.Read(buf[:]) //第一次执行Read读取4个unicode字符
        fmt.Println(string(buf[:n]), n, err)
        rn := r.Buffered()
        fmt.Printf("还可以从缓冲区中读取%d个字节
    ", rn)
        n, err = r.Read(buf[:]) //第二次读取了剩余的3个unicode字符
        fmt.Println(string(buf[:n]), n, err)
        rn = r.Buffered()
        fmt.Printf("还可以从缓冲区中读取%d个字节
    ", rn)
    }

    测试结果为:

    中华人民 12 <nil>
    还可以从缓冲区中读取9个字节
    共和国 9 <nil>
    还可以从缓冲区中读取0个字节

    (11)Peek()方法。功能是读取指定字节数的数据,这些被读取的数据不会从缓冲区中清除。在下次读取之后,本次返回的字节切片会失效。如果Peek返回的字节数不足n字节,则会同时返回一个错误说明原因;如果n比缓冲区要大,则错误为ErrBufferFull。该方法示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        data := []byte("中华人民共和国")
        rd := bytes.NewReader(data)
        r := bufio.NewReader(rd)
        b1, err := r.Peek(9)
        fmt.Println(string(b1), err)
        b1, err = r.Peek(18)
        fmt.Println(string(b1), err)
        b1, err = r.Peek(27)
        fmt.Println(string(b1), err)
    }

    测试结果为:

    中华人 <nil>
    中华人民共和 <nil>
    中华人民共和国 EOF

    (12)WriteTo()

    3_3.Writer对象

    Writer对象可以对数据I/O接口io.Writer进行输出缓冲操作,Writer结构定义如下:

    type Writer struct {
            // contains filtered or unexported fields
    }

    默认情况下Writer对象没有定义初始值,如果输出缓冲过程中发生错误,则数据写入操作立刻被终止,后续的写操作都会返回写入异常错误。

    3_3_1.Writer对象创建函数

    Writer对象创建函数共有两个:NewWriter()和NewWriterSize(),下面分别介绍:

    (1)NewWriter()函数。功能是按照默认缓冲区创建Writer对象,Writer对象会将缓冲区的数据批量写入底层io.Writer接口。该函数的声明如下:

    	func NewWriter(wr io.Writer) *Writer

    在函数中,参数wr是io.Writer接口,Writer对象会数据写入该接口。

    (2)NewWriterSize()函数。功能是按照指定的缓冲区长度创建Writer对象,Writer对象会将缓存的数据批量写入底层io.Writer接口。该函数的原型声明如下:

    	func NewWriterSize(wr io.Writer, size int) *Writer

    在函数主公,参数wr是io.Writer接口,参数size是指定的缓冲区字节长度.

    3_3_2.Writer对象操作函数

    Writer对象的操作方法共有8个:Available()、Buffered()、Flush()、Write()、WriteByte()、WriteRune()、WriteString()、和ReadFrom().它们的原型声明如下:

    	func (b *Writer) Available() int
    	func (b *Writer) Buffered() int
    	func (b *Writer) Flush() errorf	
    	func (b *Writer) Write(p []byte) (nn int, err error)
    	func (b *Writer) WriteByte(c byte) error
    	func (b *Writer) WriteRune(r rune) (size int, err error)
    	func (b *Writer) WriteString(s string) (int, error)
    	func (b *Writer) ReadFrom(r io.Reader) (n int64, err error)

    (1)Available()方法。功能是返回缓冲区中未使用的字节数。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        p := []byte("Hello,world!")
        fmt.Println("写入前为使用的缓冲区为:", w.Available())
        w.Write(p)
        fmt.Printf("写入%q后,未使用的缓冲区为:%d
    ", string(p), w.Available())
    }

    测试结果为:

    写入前为使用的缓冲区为: 4096
    写入"Hello,world!"后,未使用的缓冲区为:4084

    (2)Buffered()方法。功能是返回已写入当前缓冲区中的字节数,示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        p := []byte("Hello,world!")
        fmt.Println("写入前写入字节数为:", w.Buffered())
        w.Write(p)
        fmt.Printf("写入%q后,写入的字节数为:%d
    ", string(p), w.Buffered())
        w.Flush()
        fmt.Println("执行Flush方法后,写入的字节数为:", w.Buffered())
    }

    测试结果为:

    写入前写入字节数为: 0
    写入"Hello,world!"后,写入的字节数为:12
    执行Flush方法后,写入的字节数为: 0

    (3)Flush()方法。功能是把缓冲区中的数据写入底层的io.Writer,并返回错误信息。如果成功写入,error返回nil,否则error返回错误原因。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        p := []byte("Hello,world!")
        w.Write(p)
        fmt.Printf("未执行Flush缓冲区输出%q.
    ", string(wr.Bytes()))
        w.Flush()
        fmt.Printf("执行Flush后,缓冲区输出%q.", string(wr.Bytes()))
    }

    测试结果为:

    未执行Flush缓冲区输出"".
    执行Flush后,缓冲区输出"Hello,world!".

    (4)Write()方法。功能是把字节切片p写入缓冲区,返回写入的字节数nn。如果nn小于len(p),则同时返回一个错误原因。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        p := []byte("Hello,world!")
        n, err := w.Write(p)
        w.Flush()
        fmt.Println(string(wr.Bytes()), n, err)
    }

    测试结果为:

    Hello,world! 12 <nil>

    (5)WriteByte()方法。功能是写入一个字节,如果成功写入,error返回nil,否则返回错误原因。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        var c byte = 'G'
        err := w.WriteByte(c)
        w.Flush()
        fmt.Println(string(wr.Bytes()), err)
    }

    测试结果为:

    G <nil>

    (6)WriteRune()方法。功能是以UTF-8编码写入一个Unicode字符,返回写入的字节数和错误信息。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        var r rune = '中'
        size, err := w.WriteRune(r)
        w.Flush()
        fmt.Println(string(wr.Bytes()), size, err)
    }

    测试结果为:

    中 3 <nil>

    (7)WriteString()方法。功能是写入一个字符串,并返回写入的字节数和错误信息。如果返回的字节数小于len(s),则同时返回一个错误说明原因。示例如下:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
    )
    
    func main() {
        wr := bytes.NewBuffer(nil)
        w := bufio.NewWriter(wr)
        s := "Hello,world!"
        n, err := w.WriteString(s)
        w.Flush()
        fmt.Println(string(wr.Bytes()), n, err)
    }

    测试结果为:

    Hello,world! 12 <nil>
  • 相关阅读:
    http缓存机制与原理
    BFC与浮动
    05ICMP协议与ARP协议(IP协议中重要协议)
    04IP编址(网络层)
    03以太网帧结构(链路层 IEEE802.3)
    02传输介质简介
    shell 脚本 2
    shell 脚本 1
    shell 中时间 表达
    sed 行编辑器
  • 原文地址:https://www.cnblogs.com/Mike-zh/p/3793685.html
Copyright © 2020-2023  润新知