【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字节\n", string(s), len(s))
    fmt.Printf("转换后字符串 %q长度: %d字节\n", 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\n", sep, s, bytes.Index(s, sep))
    fmt.Printf("切片%q的任一字符在%q中的位置索引是: %d\n", chars, s, bytes.IndexAny(s, chars))
    fmt.Printf("byte型字符%q在%q中的位置索引是: %d\n", c, s, bytes.IndexByte(s, c))
    fmt.Printf("切片%q中第一个符合f()字符索引是: %d\n", s, bytes.IndexFunc(s, f))
    fmt.Printf("rune型字符%q在%q中的位置索引是: %d\n", r, s, bytes.IndexRune(s, r))

    fmt.Printf("切片%q在%q中最后的位置索引是: %d\n", sep, s, bytes.LastIndex(s, sep))
    fmt.Printf("切片%q的任一字符在%q中最后的位置索引是:%d\n", chars, s, bytes.LastIndexAny(s, chars))
    fmt.Printf("切片%q中最后一个符合f()字符索引是: %d\n", 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\n", f)
    }
    for _, f := range bytes.SplitN(s, sep, 0) {
        fmt.Printf("%q\n", 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('\n')或者ReadString('\n').ReadLine试图返回一行,不包括结尾的回车字符。如果一行太长了(超过缓冲区长度),canshu isPrefix会 设置为true并且只返回前面的数据,剩余的数据会在以后的调用中返回。当返回最后一行数据时,参数isPrefix会设置为false。返回的字节切片只在下一次调用ReadLine前有效。ReadLine或者返回一个非空的字节切片或者返回一个错误。但他们不会同时返回。示例如下:

package main

import (
    "bufio"
    "bytes"
    "fmt"
)

func main() {
    data := []byte("Golang is a beautiful language.\r\n 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个字节\n", rn)
    n, err = r.Read(buf[:]) //第二次读取了剩余的3个unicode字符
    fmt.Println(string(buf[:n]), n, err)
    rn = r.Buffered()
    fmt.Printf("还可以从缓冲区中读取%d个字节\n", 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\n", 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\n", 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.\n", 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>
posted @ 2014-07-05 20:13  Mike_zh  阅读(2343)  评论(0编辑  收藏  举报